forked from apache/cassandra-gocql-driver
-
Notifications
You must be signed in to change notification settings - Fork 60
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 #313 from illia-li/il/fix/marshal/float
Fix `float` marshal, unmarshall functions
- Loading branch information
Showing
8 changed files
with
383 additions
and
110 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,24 @@ | ||
package float | ||
|
||
import ( | ||
"reflect" | ||
) | ||
|
||
func Marshal(value interface{}) ([]byte, error) { | ||
switch v := value.(type) { | ||
case nil: | ||
return nil, nil | ||
case float32: | ||
return EncFloat32(v) | ||
case *float32: | ||
return EncFloat32R(v) | ||
default: | ||
// Custom types (type MyFloat float32) 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,54 @@ | ||
package float | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"unsafe" | ||
) | ||
|
||
func EncFloat32(v float32) ([]byte, error) { | ||
return encFloat32(v), nil | ||
} | ||
|
||
func EncFloat32R(v *float32) ([]byte, error) { | ||
if v == nil { | ||
return nil, nil | ||
} | ||
return encFloat32R(v), nil | ||
} | ||
|
||
func EncReflect(v reflect.Value) ([]byte, error) { | ||
switch v.Kind() { | ||
case reflect.Float32: | ||
return encFloat32(float32(v.Float())), nil | ||
default: | ||
return nil, fmt.Errorf("failed to marshal float: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
} | ||
|
||
func EncReflectR(v reflect.Value) ([]byte, error) { | ||
if v.IsNil() { | ||
return nil, nil | ||
} | ||
return EncReflect(v.Elem()) | ||
} | ||
|
||
func encFloat32(v float32) []byte { | ||
return encUint32(floatToUint(v)) | ||
} | ||
|
||
func encFloat32R(v *float32) []byte { | ||
return encUint32(floatToUintR(v)) | ||
} | ||
|
||
func encUint32(v uint32) []byte { | ||
return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} | ||
} | ||
|
||
func floatToUint(v float32) uint32 { | ||
return *(*uint32)(unsafe.Pointer(&v)) | ||
} | ||
|
||
func floatToUintR(v *float32) uint32 { | ||
return *(*uint32)(unsafe.Pointer(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,29 @@ | ||
package float | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
) | ||
|
||
func Unmarshal(data []byte, value interface{}) error { | ||
switch v := value.(type) { | ||
case nil: | ||
return nil | ||
case *float32: | ||
return DecFloat32(data, v) | ||
case **float32: | ||
return DecFloat32R(data, v) | ||
default: | ||
// Custom types (type MyFloat float32) 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 float: unsupported value type (%T)(%[1]v)", v) | ||
} | ||
if rt.Elem().Kind() != reflect.Ptr { | ||
return DecReflect(data, rv) | ||
} | ||
return DecReflectR(data, rv) | ||
} | ||
} |
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,126 @@ | ||
package float | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"unsafe" | ||
) | ||
|
||
var errWrongDataLen = fmt.Errorf("failed to unmarshal float: the length of the data should be 0 or 4") | ||
|
||
func errNilReference(v interface{}) error { | ||
return fmt.Errorf("failed to unmarshal float: can not unmarshal into nil reference(%T)(%[1]v)", v) | ||
} | ||
|
||
func DecFloat32(p []byte, v *float32) error { | ||
if v == nil { | ||
return errNilReference(v) | ||
} | ||
switch len(p) { | ||
case 0: | ||
*v = 0 | ||
case 4: | ||
*v = decFloat32(p) | ||
default: | ||
return errWrongDataLen | ||
} | ||
return nil | ||
} | ||
|
||
func DecFloat32R(p []byte, v **float32) error { | ||
if v == nil { | ||
return errNilReference(v) | ||
} | ||
switch len(p) { | ||
case 0: | ||
if p == nil { | ||
*v = nil | ||
} else { | ||
*v = new(float32) | ||
} | ||
case 4: | ||
*v = decFloat32R(p) | ||
default: | ||
return errWrongDataLen | ||
} | ||
return nil | ||
} | ||
|
||
func DecReflect(p []byte, v reflect.Value) error { | ||
if v.IsNil() { | ||
return errNilReference(v) | ||
} | ||
|
||
switch v = v.Elem(); v.Kind() { | ||
case reflect.Float32: | ||
return decReflectFloat32(p, v) | ||
default: | ||
return fmt.Errorf("failed to unmarshal float: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
} | ||
|
||
func DecReflectR(p []byte, v reflect.Value) error { | ||
if v.IsNil() { | ||
return errNilReference(v) | ||
} | ||
|
||
switch v.Type().Elem().Elem().Kind() { | ||
case reflect.Float32: | ||
return decReflectFloat32R(p, v) | ||
default: | ||
return fmt.Errorf("failed to unmarshal float: unsupported value type (%T)(%[1]v)", v.Interface()) | ||
} | ||
} | ||
|
||
func decReflectFloat32(p []byte, v reflect.Value) error { | ||
switch len(p) { | ||
case 0: | ||
v.SetFloat(0) | ||
case 4: | ||
v.SetFloat(float64(decFloat32(p))) | ||
default: | ||
return errWrongDataLen | ||
} | ||
return nil | ||
} | ||
|
||
func decReflectFloat32R(p []byte, v reflect.Value) error { | ||
switch len(p) { | ||
case 0: | ||
v.Elem().Set(decReflectNullableR(p, v)) | ||
case 4: | ||
val := reflect.New(v.Type().Elem().Elem()) | ||
val.Elem().SetFloat(float64(decFloat32(p))) | ||
v.Elem().Set(val) | ||
default: | ||
return errWrongDataLen | ||
} | ||
return nil | ||
} | ||
|
||
func decReflectNullableR(p []byte, v reflect.Value) reflect.Value { | ||
if p == nil { | ||
return reflect.Zero(v.Elem().Type()) | ||
} | ||
return reflect.New(v.Type().Elem().Elem()) | ||
} | ||
|
||
func decFloat32(p []byte) float32 { | ||
return uint32ToFloat(decUint32(p)) | ||
} | ||
|
||
func decFloat32R(p []byte) *float32 { | ||
return uint32ToFloatR(decUint32(p)) | ||
} | ||
|
||
func uint32ToFloat(v uint32) float32 { | ||
return *(*float32)(unsafe.Pointer(&v)) | ||
} | ||
|
||
func uint32ToFloatR(v uint32) *float32 { | ||
return (*float32)(unsafe.Pointer(&v)) | ||
} | ||
|
||
func decUint32(p []byte) uint32 { | ||
return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]) | ||
} |
Oops, something went wrong.