示例#1
0
文件: lucy.go 项目: lazycrazyowl/lucy
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
}
示例#2
0
文件: lucy.go 项目: kidaa/lucy
//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
}