forked from apache/cassandra-gocql-driver
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix
inet
marshal, unmarshal functions
- Loading branch information
Showing
5 changed files
with
806 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package inet | ||
|
||
import ( | ||
"net" | ||
"reflect" | ||
) | ||
|
||
func Marshal(value interface{}) ([]byte, error) { | ||
switch v := value.(type) { | ||
case nil: | ||
return nil, nil | ||
case []byte: | ||
return EncBytes(v) | ||
case *[]byte: | ||
return EncBytesR(v) | ||
case net.IP: | ||
return EncNetIP(v) | ||
case *net.IP: | ||
return EncNetIPr(v) | ||
case [4]byte: | ||
return EncArray4(v) | ||
case *[4]byte: | ||
return EncArray4R(v) | ||
case [16]byte: | ||
return EncArray16(v) | ||
case *[16]byte: | ||
return EncArray16R(v) | ||
case string: | ||
return EncString(v) | ||
case *string: | ||
return EncStringR(v) | ||
default: | ||
// Custom types (type MyIP []byte) can be serialized only via `reflect` package. | ||
// Later, when generic-based serialization is introduced we can do that via generics. | ||
rv := reflect.TypeOf(value) | ||
if rv.Kind() != reflect.Ptr { | ||
return EncReflect(reflect.ValueOf(v)) | ||
} | ||
return EncReflectR(reflect.ValueOf(v)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
package inet | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"reflect" | ||
) | ||
|
||
func EncBytes(v []byte) ([]byte, error) { | ||
switch len(v) { | ||
case 0: | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return make([]byte, 0), nil | ||
case 4: | ||
tmp := make([]byte, 4) | ||
copy(tmp, v) | ||
return tmp, nil | ||
case 16: | ||
tmp := make([]byte, 16) | ||
copy(tmp, v) | ||
return tmp, nil | ||
default: | ||
return nil, fmt.Errorf("failed to marshal inet: the ([]byte) length can be 0,4,16") | ||
} | ||
} | ||
|
||
func EncBytesR(v *[]byte) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return EncBytes(*v) | ||
} | ||
|
||
func EncNetIP(v net.IP) ([]byte, error) { | ||
switch len(v) { | ||
case 0: | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return make([]byte, 0), nil | ||
case 4, 16: | ||
t := v.To4() | ||
if t == nil { | ||
return v.To16(), nil | ||
} | ||
return t, nil | ||
default: | ||
return nil, fmt.Errorf("failed to marshal inet: the (net.IP) length can be 0,4,16") | ||
} | ||
} | ||
|
||
func EncNetIPr(v *net.IP) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return EncNetIP(*v) | ||
} | ||
|
||
func EncArray16(v [16]byte) ([]byte, error) { | ||
tmp := make([]byte, 16) | ||
copy(tmp, v[:]) | ||
return tmp, nil | ||
} | ||
|
||
func EncArray16R(v *[16]byte) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return EncArray16(*v) | ||
} | ||
|
||
func EncArray4(v [4]byte) ([]byte, error) { | ||
tmp := make([]byte, 4) | ||
copy(tmp, v[:]) | ||
return tmp, nil | ||
} | ||
|
||
func EncArray4R(v *[4]byte) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return EncArray4(*v) | ||
} | ||
|
||
func EncString(v string) ([]byte, error) { | ||
if len(v) == 0 { | ||
return nil, nil | ||
} | ||
b := net.ParseIP(v) | ||
if b != nil { | ||
t := b.To4() | ||
if t == nil { | ||
return b.To16(), nil | ||
} | ||
return t, nil | ||
} | ||
return nil, fmt.Errorf("failed to marshal inet: invalid IP string %s", v) | ||
} | ||
|
||
func EncStringR(v *string) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return EncString(*v) | ||
} | ||
|
||
func EncReflect(v reflect.Value) ([]byte, error) { | ||
switch v.Kind() { | ||
case reflect.Array: | ||
if l := v.Len(); v.Type().Elem().Kind() != reflect.Uint8 || (l != 16 && l != 4) { | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
nv := reflect.New(v.Type()) | ||
nv.Elem().Set(v) | ||
return nv.Elem().Bytes(), nil | ||
case reflect.Slice: | ||
if v.Type().Elem().Kind() != reflect.Uint8 { | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
return encReflectBytes(v) | ||
case reflect.String: | ||
return encReflectString(v) | ||
case reflect.Struct: | ||
if v.Type().String() == "gocql.unsetColumn" { | ||
return nil, nil | ||
} | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
default: | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
} | ||
|
||
func EncReflectR(v reflect.Value) ([]byte, error) { | ||
if v.IsNil() { | ||
return nil, nil | ||
} | ||
switch ev := v.Elem(); ev.Kind() { | ||
case reflect.Array: | ||
if l := v.Len(); ev.Type().Elem().Kind() != reflect.Uint8 || (l != 16 && l != 4) { | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
return v.Elem().Bytes(), nil | ||
case reflect.Slice: | ||
if ev.Type().Elem().Kind() != reflect.Uint8 { | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
return encReflectBytes(ev) | ||
case reflect.String: | ||
return encReflectString(ev) | ||
default: | ||
return nil, fmt.Errorf("failed to marshal inet: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
} | ||
|
||
func encReflectString(v reflect.Value) ([]byte, error) { | ||
val := v.String() | ||
if len(val) == 0 { | ||
return nil, nil | ||
} | ||
b := net.ParseIP(val) | ||
if b != nil { | ||
t := b.To4() | ||
if t == nil { | ||
return b.To16(), nil | ||
} | ||
return t, nil | ||
} | ||
return nil, fmt.Errorf("failed to marshal inet: invalid IP string (%T)(%[1]v)", v.Interface()) | ||
} | ||
|
||
func encReflectBytes(v reflect.Value) ([]byte, error) { | ||
val := v.Bytes() | ||
switch len(val) { | ||
case 0: | ||
if val == nil { | ||
return nil, nil | ||
} | ||
return make([]byte, 0), nil | ||
case 4: | ||
tmp := make([]byte, 4) | ||
copy(tmp, val) | ||
return tmp, nil | ||
case 16: | ||
tmp := make([]byte, 16) | ||
copy(tmp, val) | ||
return tmp, nil | ||
default: | ||
return nil, fmt.Errorf("failed to marshal inet: the (%T) length can be 0,4,16", v.Interface()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package inet | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"reflect" | ||
) | ||
|
||
func Unmarshal(data []byte, value interface{}) error { | ||
switch v := value.(type) { | ||
case nil: | ||
return nil | ||
case *[]byte: | ||
return DecBytes(data, v) | ||
case **[]byte: | ||
return DecBytesR(data, v) | ||
case *net.IP: | ||
return DecNetIP(data, v) | ||
case **net.IP: | ||
return DecNetIPr(data, v) | ||
case *[4]byte: | ||
return DecArray4(data, v) | ||
case **[4]byte: | ||
return DecArray4R(data, v) | ||
case *[16]byte: | ||
return DecArray16(data, v) | ||
case **[16]byte: | ||
return DecArray16R(data, v) | ||
case *string: | ||
return DecString(data, v) | ||
case **string: | ||
return DecStringR(data, v) | ||
default: | ||
// Custom types (type MyIP []byte) can be deserialized only via `reflect` package. | ||
// Later, when generic-based serialization is introduced we can do that via generics. | ||
rv := reflect.ValueOf(value) | ||
rt := rv.Type() | ||
if rt.Kind() != reflect.Ptr { | ||
return fmt.Errorf("failed to unmarshal inet: unsupported value type (%T)(%[1]v)", v) | ||
} | ||
if rt.Elem().Kind() != reflect.Ptr { | ||
return DecReflect(data, rv) | ||
} | ||
return DecReflectR(data, rv) | ||
} | ||
} |
Oops, something went wrong.