Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 6e034592a0
Fetching contributors…

Cannot retrieve contributors at this time

166 lines (147 sloc) 4.237 kb
package gossie
import (
"errors"
"fmt"
"reflect"
"sync"
)
type structInspection struct {
rtype reflect.Type
orderedFields []*field
goFields map[string]*field
cassandraFields map[string]*field
globalTags map[string]string
}
type field struct {
name string
index int
cassandraName string
cassandraType TypeDesc
}
var recognizedGlobalTags []string = []string{"mapping", "cf", "key", "cols", "value"}
func newField(index int, sf reflect.StructField) (*field, error) {
// ignore anon fields
if sf.Anonymous || sf.Name == "" {
return nil, nil
}
if tagType := sf.Tag.Get("skip"); tagType == "true" {
return nil, nil
}
name := sf.Name
cassandraType := defaultType(sf.Type)
if cassandraType == UnknownType {
return nil, errors.New(fmt.Sprint("Field ", name, " has unsupported type"))
}
if tagType := sf.Tag.Get("type"); tagType != "" {
cassandraType = parseTypeDesc(tagType)
}
cassandraName := name
if tagName := sf.Tag.Get("name"); tagName != "" {
cassandraName = tagName
}
return &field{name, index, cassandraName, cassandraType}, nil
}
func (f *field) marshalName() ([]byte, error) {
b, err := Marshal(f.cassandraName, UTF8Type)
if err != nil {
return nil, errors.New(fmt.Sprint("Error marshaling field name for field ", f.name, ":", err))
}
return b, nil
}
func (f *field) marshalValue(structValue *reflect.Value) ([]byte, error) {
v := structValue.Field(f.index)
b, err := Marshal(v.Interface(), f.cassandraType)
if err != nil {
return nil, errors.New(fmt.Sprint("Error marshaling field value for field ", f.name, ":", err))
}
return b, nil
}
func (f *field) unmarshalValue(b []byte, structValue *reflect.Value) error {
v := structValue.Field(f.index)
if !v.CanAddr() {
return errors.New(fmt.Sprint("Cannot obtain pointer to field ", f.name))
}
vp := v.Addr()
err := Unmarshal(b, f.cassandraType, vp.Interface())
if err != nil {
return errors.New(fmt.Sprint("Error unmarshaling field ", f.name, ":", err))
}
return nil
}
func newStructInspection(t reflect.Type) (*structInspection, error) {
si := &structInspection{
rtype: t,
orderedFields: make([]*field, 0),
goFields: make(map[string]*field, 0),
cassandraFields: make(map[string]*field, 0),
globalTags: make(map[string]string),
}
n := t.NumField()
for i := 0; i < n; i++ {
sf := t.Field(i)
for _, t := range recognizedGlobalTags {
if v := sf.Tag.Get(t); v != "" {
si.globalTags[t] = v
}
}
f, err := newField(i, sf)
if err != nil {
return nil, errors.New(fmt.Sprint("Error in struct ", t.Name(), ": ", err))
}
if f != nil {
si.orderedFields = append(si.orderedFields, f)
si.goFields[f.name] = f
si.cassandraFields[f.cassandraName] = f
}
}
return si, nil
}
var structInspectionCache map[reflect.Type]*structInspection
var structInspectionCacheMutex *sync.Mutex = new(sync.Mutex)
func inspectStruct(v *reflect.Value) (*structInspection, error) {
var si *structInspection
var err error
found := false
t := v.Type()
structInspectionCacheMutex.Lock()
if structInspectionCache == nil {
structInspectionCache = make(map[reflect.Type]*structInspection)
}
if si, found = structInspectionCache[t]; !found {
si, err = newStructInspection(t)
if err != nil {
structInspectionCache[t] = si
}
}
structInspectionCacheMutex.Unlock()
return si, err
}
func validStruct(source interface{}) (*reflect.Value, error) {
// always work with a pointer to struct
vp := reflect.ValueOf(source)
if vp.Kind() != reflect.Ptr {
return nil, errors.New("Passed source is not a pointer to a struct")
}
if vp.IsNil() {
return nil, errors.New("Passed source is not a pointer to a struct")
}
v := reflect.Indirect(vp)
if v.Kind() != reflect.Struct {
return nil, errors.New("Passed source is not a pointer to a struct")
}
if !v.CanSet() {
return nil, errors.New("Cannot modify the passed struct instance")
}
return &v, nil
}
func validateAndInspectStruct(source interface{}) (*reflect.Value, *structInspection, error) {
v, err := validStruct(source)
if err != nil {
return nil, nil, err
}
si, err := inspectStruct(v)
if err != nil {
return nil, nil, err
}
return v, si, nil
}
Jump to Line
Something went wrong with that request. Please try again.