Exemple #1
0
func (obj *HitsIMP) Next(hit interface{}) bool {
	self := ((*C.lucy_Hits)(unsafe.Pointer(obj.TOPTR())))
	// TODO: accept a HitDoc object and populate score.

	// Get reflection value and type for the supplied struct.
	var hitValue reflect.Value
	if reflect.ValueOf(hit).Kind() == reflect.Ptr {
		temp := reflect.ValueOf(hit).Elem()
		if temp.Kind() == reflect.Struct {
			if temp.CanSet() {
				hitValue = temp
			}
		}
	}
	if hitValue == (reflect.Value{}) {
		mess := fmt.Sprintf("Arg not writeable struct pointer: %v",
			reflect.TypeOf(hit))
		obj.err = clownfish.NewErr(mess)
		return false
	}

	var docC *C.lucy_HitDoc
	errCallingNext := clownfish.TrapErr(func() {
		docC = C.LUCY_Hits_Next(self)
	})
	if errCallingNext != nil {
		obj.err = errCallingNext
		return false
	}
	if docC == nil {
		return false
	}
	defer C.cfish_dec_refcount(unsafe.Pointer(docC))

	fields := (*C.cfish_Hash)(unsafe.Pointer(C.LUCY_HitDoc_Get_Fields(docC)))
	iterator := C.cfish_HashIter_new(fields)
	defer C.cfish_dec_refcount(unsafe.Pointer(iterator))
	for C.CFISH_HashIter_Next(iterator) {
		keyC := C.CFISH_HashIter_Get_Key(iterator)
		valC := C.CFISH_HashIter_Get_Value(iterator)
		key := clownfish.CFStringToGo(unsafe.Pointer(keyC))
		val := clownfish.CFStringToGo(unsafe.Pointer(valC))
		match := func(name string) bool {
			return strings.EqualFold(key, name)
		}
		structField := hitValue.FieldByNameFunc(match)
		if structField != (reflect.Value{}) {
			structField.SetString(val)
		}
	}
	return true
}
Exemple #2
0
func goToHash(value interface{}, nullable bool) unsafe.Pointer {
	switch v := value.(type) {
	case map[string]interface{}:
		if v == nil {
			if nullable {
				return nil
			}
		} else {
			size := len(v)
			hash := C.cfish_Hash_new(C.size_t(size))
			for key, val := range v {
				newVal := GoToClownfish(val, nil, true)
				keySize := len(key)
				keyStr := C.CString(key)
				cfKey := C.cfish_Str_new_steal_utf8(keyStr, C.size_t(keySize))
				defer C.cfish_dec_refcount(unsafe.Pointer(cfKey))
				C.CFISH_Hash_Store(hash, cfKey, (*C.cfish_Obj)(newVal))
			}
			return unsafe.Pointer(hash)
		}
	case Obj:
		certifyCF(v, C.CFISH_HASH, nullable)
		return unsafe.Pointer(C.cfish_incref(unsafe.Pointer(v.TOPTR())))
	}
	mess := fmt.Sprintf("Can't convert %T to clownfish.Hash", value)
	panic(NewErr(mess))
}
Exemple #3
0
//export GOLUCY_Inverter_Invert_Doc
func GOLUCY_Inverter_Invert_Doc(inverter *C.lucy_Inverter, doc *C.lucy_Doc) {
	ivars := C.lucy_Inverter_IVARS(inverter)
	fields := (*C.cfish_Hash)(C.LUCY_Doc_Get_Fields(doc))

	// Prepare for the new doc.
	C.LUCY_Inverter_Set_Doc(inverter, doc)

	// Extract and invert the doc's fields.
	iter := C.cfish_HashIter_new(fields)
	for C.CFISH_HashIter_Next(iter) {
		field := C.CFISH_HashIter_Get_Key(iter)
		obj := C.CFISH_HashIter_Get_Value(iter)
		if obj == nil {
			mess := "Invalid nil value for field" + clownfish.CFStringToGo(unsafe.Pointer(field))
			panic(clownfish.NewErr(mess))
		}

		inventry := fetchEntry(ivars, field)
		inventryIvars := C.lucy_InvEntry_IVARS(inventry)
		fieldType := inventryIvars._type

		// Get the field value.
		var expectedType *C.cfish_Class
		switch C.LUCY_FType_Primitive_ID(fieldType) & C.lucy_FType_PRIMITIVE_ID_MASK {
		case C.lucy_FType_TEXT:
			expectedType = C.CFISH_STRING
		case C.lucy_FType_BLOB:
			expectedType = C.CFISH_BLOB
		case C.lucy_FType_INT32:
			expectedType = C.CFISH_INTEGER
		case C.lucy_FType_INT64:
			expectedType = C.CFISH_INTEGER
		case C.lucy_FType_FLOAT32:
			expectedType = C.CFISH_FLOAT
		case C.lucy_FType_FLOAT64:
			expectedType = C.CFISH_FLOAT
		default:
			panic(clownfish.NewErr("Internal Lucy error: bad type id for field " +
				clownfish.CFStringToGo(unsafe.Pointer(field))))
		}
		if !C.cfish_Obj_is_a(obj, expectedType) {
			className := C.cfish_Obj_get_class_name((*C.cfish_Obj)(unsafe.Pointer(fieldType)))
			mess := fmt.Sprintf("Invalid type for field '%s': '%s'",
				clownfish.CFStringToGo(unsafe.Pointer(field)),
				clownfish.CFStringToGo(unsafe.Pointer(className)))
			panic(clownfish.NewErr(mess))
		}
		if inventryIvars.value != obj {
			C.cfish_decref(unsafe.Pointer(inventryIvars.value))
			inventryIvars.value = C.cfish_inc_refcount(unsafe.Pointer(obj))
		}

		C.LUCY_Inverter_Add_Field(inverter, inventry)
	}
	C.cfish_dec_refcount(unsafe.Pointer(iter))
}
Exemple #4
0
func StringToGo(ptr unsafe.Pointer) string {
	cfString := (*C.cfish_String)(ptr)
	if cfString == nil {
		return ""
	}
	if !C.cfish_Str_is_a(cfString, C.CFISH_STRING) {
		cfString := C.CFISH_Str_To_String(cfString)
		defer C.cfish_dec_refcount(unsafe.Pointer(cfString))
	}
	data := C.CFISH_Str_Get_Ptr8(cfString)
	size := C.CFISH_Str_Get_Size(cfString)
	if size > C.size_t(C.INT_MAX) {
		panic(fmt.Sprintf("Overflow: %d > %d", size, C.INT_MAX))
	}
	return C.GoStringN(data, C.int(size))
}
Exemple #5
0
func HashToGo(ptr unsafe.Pointer) map[string]interface{} {
	hash := (*C.cfish_Hash)(ptr)
	if hash == nil {
		return nil
	}
	class := C.cfish_Obj_get_class((*C.cfish_Obj)(ptr))
	if class != C.CFISH_HASH {
		mess := "Not a Hash: " + StringToGo(unsafe.Pointer(C.CFISH_Class_Get_Name(class)))
		panic(NewErr(mess))
	}
	size := C.CFISH_Hash_Get_Size(hash)
	m := make(map[string]interface{}, int(size))
	iter := C.cfish_HashIter_new(hash)
	defer C.cfish_dec_refcount(unsafe.Pointer(iter))
	for C.CFISH_HashIter_Next(iter) {
		key := C.CFISH_HashIter_Get_Key(iter)
		val := C.CFISH_HashIter_Get_Value(iter)
		m[StringToGo(unsafe.Pointer(key))] = ToGo(unsafe.Pointer(val))
	}
	return m
}
Exemple #6
0
func (obj *IndexerIMP) findFieldC(name string) *C.cfish_String {
	self := ((*C.lucy_Indexer)(unsafe.Pointer(obj.TOPTR())))
	if obj.fieldNames == nil {
		obj.fieldNames = make(map[string]clownfish.String)
	}
	f, ok := obj.fieldNames[name]
	if !ok {
		schema := C.LUCY_Indexer_Get_Schema(self)
		fieldList := C.LUCY_Schema_All_Fields(schema)
		defer C.cfish_dec_refcount(unsafe.Pointer(fieldList))
		for i := 0; i < int(C.CFISH_Vec_Get_Size(fieldList)); i++ {
			cfString := unsafe.Pointer(C.CFISH_Vec_Fetch(fieldList, C.size_t(i)))
			field := clownfish.CFStringToGo(cfString)
			if strings.EqualFold(name, field) {
				C.cfish_inc_refcount(cfString)
				f = clownfish.WRAPString(cfString)
				obj.fieldNames[name] = f
			}
		}
	}
	return (*C.cfish_String)(unsafe.Pointer(f.TOPTR()))
}
Exemple #7
0
func (obj *IndexerIMP) findRealField(name string) (string, error) {
	self := ((*C.lucy_Indexer)(unsafe.Pointer(obj.TOPTR())))
	if obj.fieldNames == nil {
		obj.fieldNames = make(map[string]string)
	}
	if field, ok := obj.fieldNames[name]; ok {
		return field, nil
	} else {
		schema := C.LUCY_Indexer_Get_Schema(self)
		fieldList := C.LUCY_Schema_All_Fields(schema)
		defer C.cfish_dec_refcount(unsafe.Pointer(fieldList))
		for i := 0; i < int(C.CFISH_Vec_Get_Size(fieldList)); i++ {
			cfString := unsafe.Pointer(C.CFISH_Vec_Fetch(fieldList, C.size_t(i)))
			field := clownfish.CFStringToGo(cfString)
			if strings.EqualFold(name, field) {
				obj.fieldNames[name] = field
				return field, nil
			}
		}
	}
	return "", clownfish.NewErr(fmt.Sprintf("Unknown field: '%v'", name))
}
Exemple #8
0
func doReadDocData(ddrC *C.lucy_DefaultDocReader, docID int32, doc interface{}) error {

	// Adapt for different types of "doc".
	var setField func(interface{}, string, interface{}) error
	var fields interface{}
	switch v := doc.(type) {
	case Doc:
		docC := (*C.lucy_Doc)(clownfish.Unwrap(v, "doc"))
		fieldsMap := fetchDocFields(docC)
		for field, _ := range fieldsMap {
			delete(fieldsMap, field)
		}
		fields = fieldsMap
		setField = setMapField
	case map[string]interface{}:
		for field, _ := range v {
			delete(v, field)
		}
		fields = v
		setField = setMapField
	default:
		// Get reflection value and type for the supplied struct.
		var hitValue reflect.Value
		if reflect.ValueOf(doc).Kind() == reflect.Ptr {
			temp := reflect.ValueOf(doc).Elem()
			if temp.Kind() == reflect.Struct {
				if temp.CanSet() {
					hitValue = temp
				}
			}
		}
		if hitValue == (reflect.Value{}) {
			mess := fmt.Sprintf("Arg not writeable struct pointer: %v",
				reflect.TypeOf(doc))
			return clownfish.NewErr(mess)
		}
		fields = hitValue
		setField = setStructField
	}

	ivars := C.lucy_DefDocReader_IVARS(ddrC)
	schema := ivars.schema
	datInstream := ivars.dat_in
	ixInstream := ivars.ix_in
	fieldNameCap := C.size_t(31)
	var fieldName *C.char = ((*C.char)(C.malloc(fieldNameCap + 1)))
	defer C.free(unsafe.Pointer(fieldName))

	// Get data file pointer from index, read number of fields.
	C.LUCY_InStream_Seek(ixInstream, C.int64_t(docID*8))
	start := C.LUCY_InStream_Read_U64(ixInstream)
	C.LUCY_InStream_Seek(datInstream, C.int64_t(start))
	numFields := uint32(C.LUCY_InStream_Read_C32(datInstream))

	// Decode stored data and build up the doc field by field.
	for i := uint32(0); i < numFields; i++ {
		// Read field name.
		fieldNameLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
		if fieldNameLen > fieldNameCap {
			fieldNameCap = fieldNameLen
			fieldName = ((*C.char)(C.realloc(unsafe.Pointer(fieldName), fieldNameCap+1)))
		}
		C.LUCY_InStream_Read_Bytes(datInstream, fieldName, fieldNameLen)

		// Find the Field's FieldType.
		// TODO: Creating and destroying a new string each time is
		// inefficient.  The solution should be to add a privte
		// Schema_Fetch_Type_Utf8 method which takes char* and size_t.
		fieldNameStr := C.cfish_Str_new_from_utf8(fieldName, fieldNameLen)
		fieldNameGo := C.GoStringN(fieldName, C.int(fieldNameLen))
		fieldType := C.LUCY_Schema_Fetch_Type(schema, fieldNameStr)
		C.cfish_dec_refcount(unsafe.Pointer(fieldNameStr))

		// Read the field value.
		switch C.LUCY_FType_Primitive_ID(fieldType) & C.lucy_FType_PRIMITIVE_ID_MASK {
		case C.lucy_FType_TEXT:
			valueLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
			buf := ((*C.char)(C.malloc(valueLen + 1)))
			C.LUCY_InStream_Read_Bytes(datInstream, buf, valueLen)
			val := C.GoStringN(buf, C.int(valueLen))
			err := setField(fields, fieldNameGo, val)
			if err != nil {
				return err
			}
		case C.lucy_FType_BLOB:
			valueLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
			buf := ((*C.char)(C.malloc(valueLen)))
			C.LUCY_InStream_Read_Bytes(datInstream, buf, valueLen)
			val := C.GoBytes(unsafe.Pointer(buf), C.int(valueLen))
			err := setField(fields, fieldNameGo, val)
			if err != nil {
				return err
			}
		case C.lucy_FType_FLOAT32:
			err := setField(fields, fieldNameGo, float32(C.LUCY_InStream_Read_F32(datInstream)))
			if err != nil {
				return err
			}
		case C.lucy_FType_FLOAT64:
			err := setField(fields, fieldNameGo, float64(C.LUCY_InStream_Read_F64(datInstream)))
			if err != nil {
				return err
			}
		case C.lucy_FType_INT32:
			err := setField(fields, fieldNameGo, int32(C.LUCY_InStream_Read_C32(datInstream)))
			if err != nil {
				return err
			}
		case C.lucy_FType_INT64:
			err := setField(fields, fieldNameGo, int64(C.LUCY_InStream_Read_C64(datInstream)))
			if err != nil {
				return err
			}
		default:
			return clownfish.NewErr(
				"Internal Lucy error: bad type id for field " + fieldNameGo)
		}
	}
	return nil
}
Exemple #9
0
func ClearRef(o *ObjIMP) {
	C.cfish_dec_refcount(unsafe.Pointer(o.ref))
	o.ref = 0
}
Exemple #10
0
//export GOLUCY_DefDocReader_Fetch_Doc
func GOLUCY_DefDocReader_Fetch_Doc(ddr *C.lucy_DefaultDocReader,
	docID C.int32_t) *C.lucy_HitDoc {
	ivars := C.lucy_DefDocReader_IVARS(ddr)
	schema := ivars.schema
	datInstream := ivars.dat_in
	ixInstream := ivars.ix_in
	fields := C.cfish_Hash_new(1)
	fieldNameCap := C.size_t(31)
	var fieldName *C.char = ((*C.char)(C.malloc(fieldNameCap + 1)))

	// Get data file pointer from index, read number of fields.
	C.LUCY_InStream_Seek(ixInstream, C.int64_t(docID*8))
	start := C.LUCY_InStream_Read_U64(ixInstream)
	C.LUCY_InStream_Seek(datInstream, C.int64_t(start))
	numFields := uint32(C.LUCY_InStream_Read_C32(datInstream))

	// Decode stored data and build up the doc field by field.
	for i := uint32(0); i < numFields; i++ {
		// Read field name.
		fieldNameLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
		if fieldNameLen > fieldNameCap {
			fieldNameCap = fieldNameLen
			fieldName = ((*C.char)(C.realloc(unsafe.Pointer(fieldName), fieldNameCap+1)))
		}
		C.LUCY_InStream_Read_Bytes(datInstream, fieldName, fieldNameLen)

		// Find the Field's FieldType.
		// TODO: Creating and destroying a new string each time is
		// inefficient.  The solution should be to add a privte
		// Schema_Fetch_Type_Utf8 method which takes char* and size_t.
		fieldNameStr := C.cfish_Str_new_from_utf8(fieldName, fieldNameLen)
		fieldType := C.LUCY_Schema_Fetch_Type(schema, fieldNameStr)
		C.cfish_dec_refcount(unsafe.Pointer(fieldNameStr))

		// Read the field value.
		var value *C.cfish_Obj
		switch C.LUCY_FType_Primitive_ID(fieldType) & C.lucy_FType_PRIMITIVE_ID_MASK {
		case C.lucy_FType_TEXT:
			valueLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
			buf := ((*C.char)(C.malloc(valueLen + 1)))
			C.LUCY_InStream_Read_Bytes(datInstream, buf, valueLen)
			C.null_terminate_string(buf, valueLen)
			value = ((*C.cfish_Obj)(C.cfish_Str_new_steal_utf8(buf, valueLen)))
		case C.lucy_FType_BLOB:
			valueLen := C.size_t(C.LUCY_InStream_Read_C32(datInstream))
			buf := ((*C.char)(C.malloc(valueLen)))
			C.LUCY_InStream_Read_Bytes(datInstream, buf, valueLen)
			value = ((*C.cfish_Obj)(C.cfish_Blob_new_steal(buf, valueLen)))
		case C.lucy_FType_FLOAT32:
			value = ((*C.cfish_Obj)(C.cfish_Float_new(C.double(C.LUCY_InStream_Read_F32(datInstream)))))
		case C.lucy_FType_FLOAT64:
			value = ((*C.cfish_Obj)(C.cfish_Float_new(C.LUCY_InStream_Read_F64(datInstream))))
		case C.lucy_FType_INT32:
			value = ((*C.cfish_Obj)(C.cfish_Int_new(C.int64_t(C.LUCY_InStream_Read_C32(datInstream)))))
		case C.lucy_FType_INT64:
			value = ((*C.cfish_Obj)(C.cfish_Int_new(C.int64_t(C.LUCY_InStream_Read_C64(datInstream)))))
		default:
			value = nil
			panic(clownfish.NewErr("Internal Lucy error: bad type id for field " +
				C.GoStringN(fieldName, C.int(fieldNameLen))))
		}

		// Store the value.
		C.CFISH_Hash_Store_Utf8(fields, fieldName, fieldNameLen, value)
	}
	C.free(unsafe.Pointer(fieldName))

	retval := C.lucy_HitDoc_new(unsafe.Pointer(fields), docID, 0.0)
	C.cfish_dec_refcount(unsafe.Pointer(fields))
	return retval
}