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.
Merge pull request #362 from illia-li/il/fix/marshal/inet
Fix `inet` marshal, unmarshall functions
- Loading branch information
Showing
8 changed files
with
1,066 additions
and
261 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
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()) | ||
} | ||
} |
Oops, something went wrong.