diff --git a/README.md b/README.md index ff3a23b..bf58611 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,66 @@ # Msgpack-Fatma-Ebrahim -a Go package that implements MessagePack serialization and deserialization. +a Go library that implements MessagePack serialization and deserialization. + +Check this link to learn more: https://github.com/msgpack/msgpack/blob/master/spec.md + +## Functions: +### `Serialize(elementVal any) []byte` +serializes a single element into a byte array + +### `Deserialize(value []byte) any` +deserializes a byte array into a single element + +### `Pack(obj interface{}) ([]byte, error)` +packs an object into a byte array + +### `Unpack(bytes []byte, obj interface{}) (any, error)` +unpacks a byte array into an object + + +## How to Use: +### Step 1: Install the library using `go get` + + ```bash + go get github.com/codescalersinternships/Msgpack-Fatma-Ebrahim + ``` + +This command fetches the library and adds it to your project's `go.mod` file. + +### Step 2: Import and use the library in your code + + After running `go get`, you can import the library into your project and use the functions as described: + + +``` +package main + +import ( + "fmt" + msgpack "github.com/codescalersinternships/Msgpack-Fatma-Ebrahim/pkg" +) + +type Object struct { + IsObject bool + Flag bool +} + +func main() { + object := Object{ + IsObject: true, + Flag: false, + } + + packed, err := msgpack.Pack(object) + if err != nil { + fmt.Println(err) + } + + var obj Object + _, err = msgpack.Unpack(packed, &obj) + if err != nil { + fmt.Println(err) + } + + fmt.Printf("Object: %+v\n", obj) +} +``` diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..06dec22 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,61 @@ +package main + +import ( + "fmt" + msgpack "github.com/codescalersinternships/Msgpack-Fatma-Ebrahim/pkg" +) + +func main() { + arr := make([]float32, 3) + arr[0] = 0 + arr[1] = 7.1 + arr[2] = 9.8 + + m := make(map[any]any) + m["hello"] = 10 + m["world"] = -20 + + typed_map := make(map[float32]int16) + typed_map[1.1] = 1 + typed_map[2.2] = 2 + + object := msgpack.Object{ + IsObject: true, + Flag: false, + Unum: 0, + Snum: -1000, + Fnum: 3.14, + Str: "Fatma", + Arr: arr, + Mapp: m, + Typed: typed_map, + } + + packed, err := msgpack.Pack(object) + if err != nil { + fmt.Println(err) + } + fmt.Printf("Packed: %+v\n", packed) + + var obj msgpack.Object + unpacked, err := msgpack.Unpack(packed, &obj) + if err != nil { + fmt.Println(err) + } + unpacked_val := unpacked.(map[any]any) + fmt.Printf("Unpacked: %+v\n", unpacked_val["Typed"]) + + fmt.Printf("object: %+v\n", obj) + + bytes := make([]float32, 3) + bytes[0] = 1.1 + bytes[1] = 2.2 + bytes[2] = 3.3 + + ser := msgpack.Serialize(bytes) + fmt.Printf("Serialized: %+v\n", ser) + + des := msgpack.Deserialize(ser) + fmt.Printf("Deserialized: %+v\n", des) + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..691f6b6 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/codescalersinternships/Msgpack-Fatma-Ebrahim + +go 1.25.1 diff --git a/pkg/msgpack.go b/pkg/msgpack.go new file mode 100644 index 0000000..12f2c1a --- /dev/null +++ b/pkg/msgpack.go @@ -0,0 +1,748 @@ +package msgpack + +import ( + "encoding/binary" + "math" + "reflect" +) + +const Msgpack_Nil = 0xc0 //192 +const Msgpack_False = 0xc2 //194 +const Msgpack_True = 0xc3 //195 + +const Msgpack_Bin_8 = 0xc4 //196 +const Msgpack_Bin_16 = 0xc5 //197 +const Msgpack_Bin_32 = 0xc6 //198 + +const Msgpack_Uint_8 = 0xcc //204 +const Msgpack_Uint_16 = 0xcd //205 +const Msgpack_Uint_32 = 0xce //206 +const Msgpack_Uint_64 = 0xcf //207 + +const Msgpack_Int_8 = 0xd0 //208 +const Msgpack_Int_16 = 0xd1 //209 +const Msgpack_Int_32 = 0xd2 //210 +const Msgpack_Int_64 = 0xd3 //211 + +const Msgpack_Float_32 = 0xca //202 +const Msgpack_Float_64 = 0xcb //203 + +const Msgpack_String_8 = 0xd9 //217 +const Msgpack_String_16 = 0xda //218 +const Msgpack_String_32 = 0xdb //219 + +const Msgpack_Array_16 = 0xdc //220 +const Msgpack_Array_32 = 0xdd //221 + +const Msgpack_Map_16 = 0xde //222 +const Msgpack_Map_32 = 0xdf //223 + +type Uint_8 struct { + typeByte byte + value byte +} + +type Uint struct { + typeByte byte + value []byte +} + +type Int_8 struct { + typeByte byte + value byte +} + +type Int struct { + typeByte byte + value []byte +} + +type Float struct { + typeByte byte + value []byte +} + +type String struct { + typeByte byte + value []byte + size []byte +} + +type Array struct { + typeByte byte + value []byte + size []byte +} + +type Map struct { + typeByte byte + value []byte + size []byte +} + +type Object struct { + IsObject bool + Flag bool + Unum uint8 + Snum int16 + Fnum float32 + Str string + Arr []float32 + Mapp map[any]any + Typed map[float32]int16 +} + +func encodeBool(value bool) byte { + if value { + return byte(Msgpack_True) + } else { + return byte(Msgpack_False) + } +} +func encodeUint(value uint8) Uint_8 { + return Uint_8{ + typeByte: Msgpack_Uint_8, + value: value, + } +} + +func encodeUint16(value uint16) Uint { + bytes := make([]byte, 2) + binary.BigEndian.PutUint16(bytes, value) + return Uint{ + typeByte: Msgpack_Uint_16, + value: bytes, + } +} + +func encodeUint32(value uint32) Uint { + bytes := make([]byte, 4) + binary.BigEndian.PutUint32(bytes, value) + return Uint{ + typeByte: Msgpack_Uint_32, + value: bytes, + } +} + +func encodeUint64(value uint64) Uint { + bytes := make([]byte, 8) + binary.BigEndian.PutUint64(bytes, value) + return Uint{ + typeByte: Msgpack_Uint_64, + value: bytes, + } +} + +func encodeInt(value int) Int { + bytes := make([]byte, 8) + binary.BigEndian.PutUint64(bytes, uint64(value)) + return Int{ + typeByte: Msgpack_Int_64, + value: bytes, + } +} + +func encodeInt8(value int8) Int_8 { + return Int_8{ + typeByte: Msgpack_Int_8, + value: byte(value), + } +} + +func encodeInt16(value int16) Int { + bytes := make([]byte, 2) + binary.BigEndian.PutUint16(bytes, uint16(value)) + return Int{ + typeByte: Msgpack_Int_16, + value: bytes, + } +} + +func encodeInt32(value int32) Int { + bytes := make([]byte, 4) + binary.BigEndian.PutUint32(bytes, uint32(value)) + return Int{ + typeByte: Msgpack_Int_32, + value: bytes, + } +} + +func encodeInt64(value int64) Int { + bytes := make([]byte, 8) + binary.BigEndian.PutUint64(bytes, uint64(value)) + return Int{ + typeByte: Msgpack_Int_64, + value: bytes, + } +} + +func encodeFloat32(value float32) Float { + bin := math.Float32bits(value) + bytes := make([]byte, 4) + binary.BigEndian.PutUint32(bytes, bin) + return Float{ + typeByte: Msgpack_Float_32, + value: bytes, + } +} + +func encodeFloat64(value float64) Float { + bin := math.Float64bits(value) + bytes := make([]byte, 8) + binary.BigEndian.PutUint64(bytes, bin) + return Float{ + typeByte: Msgpack_Float_64, + value: bytes, + } +} +func encodeString(value string) String { + string_8 := int(math.Pow(2, 8) - 1) + string_16 := int(math.Pow(2, 16) - 1) + string_32 := int(math.Pow(2, 32) - 1) + var size []byte + var t byte + switch { + case len(value) < string_8: + size = make([]byte, 0) + size = append(size, byte(len(value))) + t = Msgpack_String_8 + case len(value) < string_16: + size = encodeSize(len(value)) + t = Msgpack_String_16 + case len(value) < string_32: + size = encodeSize(len(value)) + t = Msgpack_String_32 + } + + bytes := []byte(value) + copy(bytes, value) + return String{ + typeByte: t, + value: bytes, + size: size, + } +} + +func encodeArray(arr any) Array { + array_value := reflect.ValueOf(arr) + array_size := array_value.Len() + + array_8 := int(math.Pow(2, 8) - 1) + array_16 := int(math.Pow(2, 16) - 1) + array_32 := int(math.Pow(2, 32) - 1) + bytes := make([]byte, 0) + var size []byte + var t byte + bin_flag := false + + if array_size != 0 { + element := array_value.Index(0).Interface() + if element != nil { + if reflect.TypeOf(element).Kind() == reflect.Uint8 { + bin_flag = true + } + } + } + if array_size <= array_16 && !bin_flag { + size = encodeSize(array_size) + t = Msgpack_Array_16 + } else if array_size <= array_32 && !bin_flag { + size = encodeSize(array_size) + t = Msgpack_Array_32 + } else if array_size <= array_8 && bin_flag { + size = make([]byte, 0) + size = append(size, byte(array_size)) + t = Msgpack_Bin_8 + } else if array_size <= array_16 && bin_flag { + size = encodeSize(array_size) + t = Msgpack_Bin_16 + } else if array_size <= array_32 && bin_flag { + size = encodeSize(array_size) + t = Msgpack_Bin_32 + } + + for i := 0; i < array_size; i++ { + element := array_value.Index(i).Interface() + if element == nil { + bytes = append(bytes, Msgpack_Nil) + continue + } + objectBytes := Serialize(element) + bytes = append(bytes, objectBytes...) + } + + return Array{ + typeByte: t, + value: bytes, + size: size, + } +} + +func encodeMap(m any) Map { + map_value := reflect.ValueOf(m) + map_size := map_value.Len() + map_16 := int(math.Pow(2, 16) - 1) + map_32 := int(math.Pow(2, 32) - 1) + + bytes := make([]byte, 0) + var size []byte + var t byte + + if map_size <= map_16 { + size = encodeSize(map_size) + t = Msgpack_Map_16 + } else if map_size <= map_32 { + size = encodeSize(map_size) + t = Msgpack_Map_32 + } + + iter := map_value.MapRange() + for iter.Next() { + key := iter.Key().Interface() + val := iter.Value().Interface() + + objectBytes := Serialize(key) + bytes = append(bytes, objectBytes...) + + objectBytes = Serialize(val) + bytes = append(bytes, objectBytes...) + } + + return Map{ + typeByte: t, + value: bytes, + size: size, + } +} + +func encodeSize(size int) []byte { + size_16 := int(math.Pow(2, 16) - 1) + size_32 := int(math.Pow(2, 32) - 1) + var sizeBytes []byte + if size <= size_16 { + sizeBytes = make([]byte, 2) + binary.BigEndian.PutUint16(sizeBytes, uint16(size)) + } else if size <= size_32 { + sizeBytes = make([]byte, 4) + binary.BigEndian.PutUint32(sizeBytes, uint32(size)) + } else { + sizeBytes = make([]byte, 8) + binary.BigEndian.PutUint64(sizeBytes, uint64(size)) + } + return sizeBytes +} + +func decodeBool(value byte) (bool, int) { + if value == byte(Msgpack_True) { + return true, 1 + } else { + return false, 1 + } +} + +func decodeUint8(value byte) (uint8, int) { + return uint8(value), 2 +} + +func decodeUint16(value []byte) (uint16, int) { + return binary.BigEndian.Uint16(value[:2]), 3 +} + +func decodeUint32(value []byte) (uint32, int) { + return binary.BigEndian.Uint32(value[:4]), 5 +} + +func decodeUint64(value []byte) (uint64, int) { + return binary.BigEndian.Uint64(value[:8]), 9 +} + +func decodeInt8(value byte) (int8, int) { + return int8(value), 2 +} + +func decodeInt16(value []byte) (int16, int) { + return int16(binary.BigEndian.Uint16(value[:2])), 3 +} + +func decodeInt32(value []byte) (int32, int) { + return int32(binary.BigEndian.Uint32(value[:4])), 5 +} + +func decodeInt64(value []byte) (int64, int) { + return int64(binary.BigEndian.Uint64(value[:8])), 9 +} + +func decodeFloat32(value []byte) (float32, int) { + bin := binary.BigEndian.Uint32(value[:4]) + return math.Float32frombits(bin), 5 +} + +func decodeFloat64(value []byte) (float64, int) { + bin := binary.BigEndian.Uint64(value[:8]) + return math.Float64frombits(bin), 9 +} + +func decodeString8(value []byte) (string, int) { + size := int(value[0]) + return string(value[1 : size+1]), 1 + 1 + size +} + +func decodeString16(value []byte) (string, int) { + size := decodeSize(value[:2]) + return string(value[2 : size+2]), 1 + 2 + size +} + +func decodeString32(value []byte) (string, int) { + size := decodeSize(value[:4]) + return string(value[4 : size+4]), 1 + 4 + size +} + +func decodeSize(value []byte) int { + if len(value) == 2 { + return int(binary.BigEndian.Uint16(value)) + } else if len(value) == 4 { + return int(binary.BigEndian.Uint32(value)) + } else if len(value) == 8 { + return int(binary.BigEndian.Uint64(value)) + } + return 0 +} + +func decodeArray16(value []byte) (any, int) { + size := decodeSize(value[:2]) + data := value[2:] + array := make([]any, size) + overallOffset := 0 + for i := 0; i < size; i++ { + element, offset := deserialize_helper(data) + array[i] = element + data = data[offset:] + overallOffset += offset + } + + return array, overallOffset + 3 +} + +func decodeArray32(value []byte) (any, int) { + size := decodeSize(value[:4]) + data := value[4:] + array := make([]any, size) + overallOffset := 0 + + for i := 0; i < size; i++ { + element, offset := deserialize_helper(data) + array[i] = element + data = data[offset:] + overallOffset += offset + } + return array, overallOffset + 5 +} + +func decodeMap16(value []byte) (any, int) { + size := decodeSize(value[:2]) + data := value[2:] + m := make(map[any]any) + overallOffset := 0 + + for i := 0; i < size; i++ { + key, offset := deserialize_helper(data) + data = data[offset:] + overallOffset += offset + val, offset := deserialize_helper(data) + data = data[offset:] + m[key] = val + overallOffset += offset + } + return m, overallOffset + 3 +} + +func decodeMap32(value []byte) (any, int) { + size := decodeSize(value[:4]) + data := value[4:] + m := make(map[any]any) + overallOffset := 0 + + for i := 0; i < size; i++ { + key, offset := deserialize_helper(data) + data = data[offset:] + overallOffset += offset + val, offset := deserialize_helper(data) + data = data[offset:] + m[key] = val + overallOffset += offset + } + return m, overallOffset + 5 +} + +func decodeBin8(value []byte) ([]byte, int) { + size := int(value[0]) + data := value[1:] + array := make([]byte, size) + overallOffset := 0 + for i := 0; i < size; i++ { + element, offset := deserialize_helper(data) + array[i] = element.(byte) + data = data[offset:] + overallOffset += offset + } + + return array, overallOffset + 2 +} + +func decodeBin16(value []byte) ([]byte, int) { + size := decodeSize(value[:2]) + data := value[2:] + array := make([]byte, size) + overallOffset := 0 + for i := 0; i < size; i++ { + element, offset := deserialize_helper(data) + array[i] = element.(byte) + data = data[offset:] + overallOffset += offset + } + + return array, overallOffset + 3 +} + +func decodeBin32(value []byte) ([]byte, int) { + size := decodeSize(value[:4]) + data := value[4:] + array := make([]byte, size) + overallOffset := 0 + for i := 0; i < size; i++ { + element, offset := deserialize_helper(data) + array[i] = element.(byte) + data = data[offset:] + overallOffset += offset + } + + return array, overallOffset + 5 +} + +func deserialize_helper(value []byte) (any, int) { + elementType := value[0] + switch elementType { + case Msgpack_True: + return decodeBool(value[0]) + case Msgpack_False: + return decodeBool(value[0]) + case Msgpack_Uint_8: + return decodeUint8(value[1]) + case Msgpack_Uint_16: + return decodeUint16(value[1:]) + case Msgpack_Uint_32: + return decodeUint32(value[1:]) + case Msgpack_Uint_64: + return decodeUint64(value[1:]) + case Msgpack_Int_8: + return decodeInt8(value[1]) + case Msgpack_Int_16: + return decodeInt16(value[1:]) + case Msgpack_Int_32: + return decodeInt32(value[1:]) + case Msgpack_Int_64: + return decodeInt64(value[1:]) + case Msgpack_Float_32: + return decodeFloat32(value[1:]) + case Msgpack_Float_64: + return decodeFloat64(value[1:]) + case Msgpack_String_8: + return decodeString8(value[1:]) + case Msgpack_String_16: + return decodeString16(value[1:]) + case Msgpack_String_32: + return decodeString32(value[1:]) + case Msgpack_Array_16: + return decodeArray16(value[1:]) + case Msgpack_Array_32: + return decodeArray32(value[1:]) + case Msgpack_Map_16: + return decodeMap16(value[1:]) + case Msgpack_Map_32: + return decodeMap32(value[1:]) + case Msgpack_Bin_8: + return decodeBin8(value[1:]) + case Msgpack_Bin_16: + return decodeBin16(value[1:]) + case Msgpack_Bin_32: + return decodeBin32(value[1:]) + case Msgpack_Nil: + return nil, 1 + } + + return nil, 0 +} + +// a function that serializes an element into a byte array +func Serialize(elementVal any) []byte { + elementValue := reflect.ValueOf(elementVal) + objectBytes := make([]byte, 0) + elementType := reflect.TypeOf(elementVal).Kind() + switch elementType { + case reflect.Bool: + objectBytes = append(objectBytes, encodeBool(elementValue.Bool())) + + case reflect.Uint8: + encodedUint := encodeUint(uint8(elementValue.Uint())) + objectBytes = append(objectBytes, encodedUint.typeByte, encodedUint.value) + + case reflect.Uint16: + encodedUint := encodeUint16(uint16(elementValue.Uint())) + objectBytes = append(objectBytes, encodedUint.typeByte) + objectBytes = append(objectBytes, encodedUint.value...) + + case reflect.Uint32: + encodedUint := encodeUint32(uint32(elementValue.Uint())) + objectBytes = append(objectBytes, encodedUint.typeByte) + objectBytes = append(objectBytes, encodedUint.value...) + + case reflect.Uint64: + encodedUint := encodeUint64(uint64(elementValue.Uint())) + objectBytes = append(objectBytes, encodedUint.typeByte) + objectBytes = append(objectBytes, encodedUint.value...) + + case reflect.Int8: + encodedInt := encodeInt8(int8(elementValue.Int())) + objectBytes = append(objectBytes, encodedInt.typeByte, encodedInt.value) + + case reflect.Int16: + encodedInt := encodeInt16(int16(elementValue.Int())) + objectBytes = append(objectBytes, encodedInt.typeByte) + objectBytes = append(objectBytes, encodedInt.value...) + + case reflect.Int32: + encodedInt := encodeInt32(int32(elementValue.Int())) + objectBytes = append(objectBytes, encodedInt.typeByte) + objectBytes = append(objectBytes, encodedInt.value...) + + case reflect.Int64: + encodedInt := encodeInt64(int64(elementValue.Int())) + objectBytes = append(objectBytes, encodedInt.typeByte) + objectBytes = append(objectBytes, encodedInt.value...) + + case reflect.Int: + encodedInt := encodeInt(int(elementValue.Int())) + objectBytes = append(objectBytes, encodedInt.typeByte) + objectBytes = append(objectBytes, encodedInt.value...) + + case reflect.Float32: + encodedFloat := encodeFloat32(float32(elementValue.Float())) + objectBytes = append(objectBytes, encodedFloat.typeByte) + objectBytes = append(objectBytes, encodedFloat.value...) + + case reflect.Float64: + encodedFloat := encodeFloat64(elementValue.Float()) + objectBytes = append(objectBytes, encodedFloat.typeByte) + objectBytes = append(objectBytes, encodedFloat.value...) + + case reflect.String: + encodedString := encodeString(elementValue.String()) + objectBytes = append(objectBytes, encodedString.typeByte) + objectBytes = append(objectBytes, encodedString.size...) + objectBytes = append(objectBytes, encodedString.value...) + + case reflect.Slice: + encodedArray := encodeArray(elementValue.Interface()) + objectBytes = append(objectBytes, encodedArray.typeByte) + objectBytes = append(objectBytes, encodedArray.size...) + objectBytes = append(objectBytes, encodedArray.value...) + + case reflect.Map: + encodedMap := encodeMap(elementValue.Interface()) + objectBytes = append(objectBytes, encodedMap.typeByte) + objectBytes = append(objectBytes, encodedMap.size...) + objectBytes = append(objectBytes, encodedMap.value...) + + default: + objectBytes = append(objectBytes, Msgpack_Nil) + } + + return objectBytes + +} + +// a function that deserializes a byte array into an element +func Deserialize(value []byte) any { + res, _ := deserialize_helper(value) + return res +} + +// a function that packs an object into a byte array +func Pack(obj interface{}) ([]byte, error) { + t := reflect.TypeOf(obj) + v := reflect.ValueOf(obj) + bytes := make([]byte, 0) + size := make([]byte, 0) + var mapType byte + if t.NumField() <= 16 { + size = encodeSize(t.NumField()) + mapType = Msgpack_Map_16 + } else if t.NumField() <= 32 { + size = encodeSize(t.NumField()) + mapType = Msgpack_Map_32 + } + bytes = append(bytes, mapType) + bytes = append(bytes, size...) + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + memberName := field.Name + memberValue := v.Field(i).Interface() + + objectBytes := Serialize(memberValue) + + nameBytes := Serialize(memberName) + + bytes = append(bytes, nameBytes...) + bytes = append(bytes, objectBytes...) + } + return bytes, nil +} + +func convertMap(m map[any]any, key_type reflect.Type, value_type reflect.Type) any { + new_map := reflect.MakeMap(reflect.MapOf(key_type, value_type)) + + for key, val := range m { + new_map.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val)) + } + return new_map.Interface() +} + +func convertArray(arr []any, value_type reflect.Type) any { + new_slice := reflect.MakeSlice(reflect.SliceOf(value_type), 0, len(arr)) + for _, val := range arr { + new_slice = reflect.Append(new_slice, reflect.ValueOf(val)) + } + return new_slice.Interface() +} + +// a function that unpacks a byte array into an object +func Unpack(bytes []byte, obj interface{}) (any, error) { + unpacked := Deserialize(bytes) + + v := reflect.ValueOf(obj).Elem() + + for key, val := range unpacked.(map[any]any) { + field := v.FieldByName(key.(string)) + packed_map_type := reflect.TypeOf(val) + object_map_type := reflect.TypeOf(field.Interface()) + + if field.Kind() == reflect.Map && object_map_type != packed_map_type { + object_map_key_type := object_map_type.Key() + object_map_val_type := object_map_type.Elem() + new_map := convertMap(val.(map[any]any), object_map_key_type, object_map_val_type) + field.Set(reflect.ValueOf(new_map)) + continue + } else if field.Kind() == reflect.Slice && object_map_type != packed_map_type { + object_slice_type := object_map_type.Elem() + new_slice := convertArray(val.([]any), object_slice_type) + field.Set(reflect.ValueOf(new_slice)) + continue + } + + field.Set(reflect.ValueOf(val)) + + } + + return unpacked, nil +} diff --git a/pkg/msgpack_test.go b/pkg/msgpack_test.go new file mode 100644 index 0000000..6fcd269 --- /dev/null +++ b/pkg/msgpack_test.go @@ -0,0 +1,626 @@ +package msgpack + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +type User struct { + Name string + Id string +} + +func TestString(t *testing.T) { + t.Run("test serialize and deserialize with string8", func(t *testing.T) { + str := strings.Repeat("x", 200) + + data_bytes := Serialize(str) + + str_type := data_bytes[0] + if str_type != 217 { + t.Errorf("Expected type of string to be 217 (str8), got %d", str_type) + } + + str_size := int(data_bytes[1]) + if str_size != 200 { + t.Errorf("Expected size of string to be 200, got %d", str_size) + } + + str_value := Deserialize(data_bytes) + if str_value != strings.Repeat("x", 200) { + t.Errorf("Expected value of string to be %s, got %s", strings.Repeat("x", 200), str_value) + } + }) + + t.Run("test serialize and deserialize with string16", func(t *testing.T) { + str := strings.Repeat("x", 260) + data_bytes := Serialize(str) + + str_type := data_bytes[0] + if str_type != 218 { + t.Errorf("Expected type of string to be 218, got %d", str_type) + } + + str_size := decodeSize(data_bytes[1:3]) + if str_size != 260 { + t.Errorf("Expected size of string to be 260, got %d", str_size) + } + + str_value := Deserialize(data_bytes) + if str_value != strings.Repeat("x", 260) { + t.Errorf("Expected value of string to be %s, got %s", strings.Repeat("x", 260), str_value) + } + + }) + + t.Run("test serialize and deserialize with string32", func(t *testing.T) { + str := strings.Repeat("x", 70000) + data_bytes := Serialize(str) + + if len(data_bytes) != 70005 { + t.Errorf("Expected size of data to be 70005, got %d", len(data_bytes)) + } + + str_type := data_bytes[0] + if str_type != 219 { + t.Errorf("Expected type of string to be 219 (str32), got %d", str_type) + } + + str_size := decodeSize(data_bytes[1:5]) + if str_size != 70000 { + t.Errorf("Expected size of string to be 70000, got %d", str_size) + } + + str_value := Deserialize(data_bytes) + if str_value != strings.Repeat("x", 70000) { + t.Errorf("Expected value of string to be %s, got %s", strings.Repeat("x", 70000), str_value) + } + }) +} + +func TestFloat(t *testing.T) { + t.Run("test serialize and deserialize with float32", func(t *testing.T) { + fnum32 := float32(3.14) + data_bytes := Serialize(fnum32) + + float_type := data_bytes[0] + if float_type != 202 { + t.Errorf("Expected type of float to be 203 (float32), got %d", float_type) + } + + float_value := Deserialize(data_bytes) + if reflect.TypeOf(float_value).Kind() != reflect.Float32 { + t.Errorf("Expected type of float to be float32, got %v", reflect.TypeOf(float_value).Kind()) + } + + if float_value != fnum32 { + t.Errorf("Expected value of float to be %f, got %f", fnum32, float_value) + } + + }) + + t.Run("test serialize and deserialize with float64", func(t *testing.T) { + fnum64 := float64(3.14) + data_bytes := Serialize(fnum64) + + float_type := data_bytes[0] + if float_type != 203 { + t.Errorf("Expected type of float to be 203 (float64), got %d", float_type) + } + + float_value := Deserialize(data_bytes) + if reflect.TypeOf(float_value).Kind() != reflect.Float64 { + t.Errorf("Expected type of float to be float64, got %v", reflect.TypeOf(float_value).Kind()) + } + + if float_value != fnum64 { + t.Errorf("Expected value of float to be %f, got %f", fnum64, float_value) + } + }) +} + +func TestInt(t *testing.T) { + t.Run("test serialize and deserialize with int8", func(t *testing.T) { + snum8 := int8(-100) + data_bytes := Serialize(snum8) + + int_type := data_bytes[0] + if int_type != 208 { + t.Errorf("Expected type of int to be 208 (int8), got %d", int_type) + } + + int_value := Deserialize(data_bytes) + if reflect.TypeOf(int_value).Kind() != reflect.Int8 { + t.Errorf("Expected type of int to be int8, got %v", reflect.TypeOf(int_value).Kind()) + } + if int_value != snum8 { + t.Errorf("Expected value of int to be %d, got %d", snum8, int_value) + } + }) + + t.Run("test serialize and deserialize with int16", func(t *testing.T) { + snum16 := int16(300) + data_bytes := Serialize(snum16) + + int_type := data_bytes[0] + if int_type != 209 { + t.Errorf("Expected type of int to be 209 (int16), got %d", int_type) + } + + int_value := Deserialize(data_bytes) + if reflect.TypeOf(int_value).Kind() != reflect.Int16 { + t.Errorf("Expected type of int to be int16, got %v", reflect.TypeOf(int_value).Kind()) + } + + if int_value != snum16 { + t.Errorf("Expected value of int to be %d, got %d", snum16, int_value) + } + }) + + t.Run("test serialize and deserialize with int32", func(t *testing.T) { + snum32 := int32(70000) + data_bytes := Serialize(snum32) + int_type := data_bytes[0] + if int_type != 210 { + t.Errorf("Expected type of int to be 210 (int32), got %d", int_type) + } + + int_value := Deserialize(data_bytes) + if reflect.TypeOf(int_value).Kind() != reflect.Int32 { + t.Errorf("Expected type of int to be int32, got %v", reflect.TypeOf(int_value).Kind()) + } + + if int_value != snum32 { + t.Errorf("Expected value of int to be %d, got %d", snum32, int_value) + } + }) + + t.Run("test serialize and deserialize with int64", func(t *testing.T) { + snum64 := int64(100) + data_bytes := Serialize(snum64) + int_type := data_bytes[0] + if int_type != 211 { + t.Errorf("Expected type of int to be 211 (int64), got %d", int_type) + } + + int_value := Deserialize(data_bytes) + if reflect.TypeOf(int_value).Kind() != reflect.Int64 { + t.Errorf("Expected type of int to be int64, got %v", reflect.TypeOf(int_value).Kind()) + } + + if int_value != snum64 { + t.Errorf("Expected value of int to be %d, got %d", snum64, int_value) + } + }) + +} + +func TestUint(t *testing.T) { + + t.Run("test serialize and deserialize with uint8", func(t *testing.T) { + unum8 := uint8(100) + data_bytes := Serialize(unum8) + + uint_type := data_bytes[0] + if uint_type != 204 { + t.Errorf("Expected type of uint to be 204 (uint8), got %d", uint_type) + } + + uint_value := Deserialize(data_bytes) + if reflect.TypeOf(uint_value).Kind() != reflect.Uint8 { + t.Errorf("Expected type of uint to be uint8, got %v", reflect.TypeOf(uint_value).Kind()) + } + }) + + t.Run("test serialize and deserialize with uint16", func(t *testing.T) { + unum16 := uint16(300) + data_bytes := Serialize(unum16) + + uint_type := data_bytes[0] + if uint_type != 205 { + t.Errorf("Expected type of uint to be 205 (uint16), got %d", uint_type) + } + + uint_value := Deserialize(data_bytes) + if reflect.TypeOf(uint_value).Kind() != reflect.Uint16 { + t.Errorf("Expected type of uint to be uint16, got %v", reflect.TypeOf(uint_value).Kind()) + } + }) + + t.Run("test serialize and deserialize with uint32", func(t *testing.T) { + unum32 := uint32(70000) + data_bytes := Serialize(unum32) + uint_type := data_bytes[0] + if uint_type != 206 { + t.Errorf("Expected type of uint to be 206 (uint32), got %d", uint_type) + } + + uint_value := Deserialize(data_bytes) + if reflect.TypeOf(uint_value).Kind() != reflect.Uint32 { + t.Errorf("Expected type of uint to be uint32, got %v", reflect.TypeOf(uint_value).Kind()) + } + }) + + t.Run("test serialize and deserialize with uint64", func(t *testing.T) { + unum64 := uint64(100) + data_bytes := Serialize(unum64) + uint_type := data_bytes[0] + if uint_type != 207 { + t.Errorf("Expected type of uint to be 207 (uint64), got %d", uint_type) + } + + uint_value := Deserialize(data_bytes) + if reflect.TypeOf(uint_value).Kind() != reflect.Uint64 { + t.Errorf("Expected type of uint to be uint64, got %v", reflect.TypeOf(uint_value).Kind()) + } + }) +} + +func TestArray(t *testing.T) { + t.Run("test serialize and deserialize with array16", func(t *testing.T) { + arr := []any{1.1, 2.2, 3.3} + data_bytes := Serialize(arr) + array_type := data_bytes[0] + + if array_type != 220 { + t.Errorf("Expected type of array to be 220 (array16), got %d", array_type) + } + + array_size := decodeSize(data_bytes[1:3]) + if array_size != 3 { + t.Errorf("Expected size of array to be 3, got %d", array_size) + } + + array_value := Deserialize(data_bytes) + if reflect.TypeOf(array_value).Kind() != reflect.Slice { + t.Errorf("Expected type of array to be slice, got %v", reflect.TypeOf(array_value).Kind()) + } + if !reflect.DeepEqual(array_value, arr) { + t.Errorf("Expected array to be %v, got %v", arr, array_value) + } + + }) + + t.Run("test serialize and deserialize with array32", func(t *testing.T) { + arr := make([]any, 70000) + for i := range arr { + arr[i] = true + } + + data_bytes := Serialize(arr) + array_type := data_bytes[0] + + if array_type != 221 { + t.Errorf("Expected type of array to be 221 (array32), got %d", array_type) + } + + array_size := decodeSize(data_bytes[1:5]) + if array_size != 70000 { + t.Errorf("Expected size of array to be 70000, got %d", array_size) + } + + array_value := Deserialize(data_bytes) + if reflect.TypeOf(array_value).Kind() != reflect.Slice { + t.Errorf("Expected type of array to be slice, got %v", reflect.TypeOf(array_value).Kind()) + } + if !reflect.DeepEqual(array_value, arr) { + t.Errorf("Expected array to be %v, got %v", arr[:5], array_value.([]any)[:5]) // print first few elements + } + }) + + t.Run("test serialize and deserialize with empty array", func(t *testing.T) { + arr := make([]any, 3) + data_bytes := Serialize(arr) + array_type := data_bytes[0] + + if array_type != 220 { + t.Errorf("Expected type of array to be 220 (array16), got %d", array_type) + } + + array_size := decodeSize(data_bytes[1:3]) + if array_size != 3 { + t.Errorf("Expected size of array to be 3, got %d", array_size) + } + + array_value := Deserialize(data_bytes) + if reflect.TypeOf(array_value).Kind() != reflect.Slice { + t.Errorf("Expected type of array to be slice, got %v", reflect.TypeOf(array_value).Kind()) + } + + array := array_value.([]any) + if array[0] != nil { + t.Errorf("Expected array element to be nil, got %v", array[0]) + } + + }) + +} + +func TestBinary(t *testing.T) { + t.Run("test serialize and deserialize with binary8", func(t *testing.T) { + arr := []byte{1, 2, 3} + data_bytes := Serialize(arr) + bin_type := data_bytes[0] + + if bin_type != 196 { + t.Errorf("Expected type of binary to be 196 (binary8), got %d", bin_type) + } + + bin_size := int(data_bytes[1]) + if bin_size != 3 { + t.Errorf("Expected size of binary to be 3, got %d", bin_size) + } + + bin_value := Deserialize(data_bytes) + if reflect.TypeOf(bin_value).Kind() != reflect.Slice { + t.Errorf("Expected type of binary to be slice, got %v", reflect.TypeOf(bin_value).Kind()) + } + if !reflect.DeepEqual(bin_value, arr) { + t.Errorf("Expected binary to be %v, got %v", arr, bin_value) + } + + }) + + t.Run("test serialize and deserialize with binary16", func(t *testing.T) { + arr := make([]byte, 500) + data_bytes := Serialize(arr) + bin_type := data_bytes[0] + + if bin_type != 197 { + t.Errorf("Expected type of binary to be 197 (binary16), got %d", bin_type) + } + + bin_size := decodeSize(data_bytes[1:3]) + if bin_size != 500 { + t.Errorf("Expected size of binary to be 500, got %d", bin_size) + } + + bin_value := Deserialize(data_bytes) + if reflect.TypeOf(bin_value).Kind() != reflect.Slice { + t.Errorf("Expected type of binary to be slice, got %v", reflect.TypeOf(bin_value).Kind()) + } + if !reflect.DeepEqual(bin_value, arr) { + t.Errorf("Expected binary to be %v, got %v", arr, bin_value) + } + + }) + + t.Run("test serialize and deserialize with binary32", func(t *testing.T) { + arr := make([]byte, 70000) + data_bytes := Serialize(arr) + bin_type := data_bytes[0] + + if bin_type != 198 { + t.Errorf("Expected type of binary to be 198 (binary32), got %d", bin_type) + } + + bin_size := decodeSize(data_bytes[1:5]) + if bin_size != 70000 { + t.Errorf("Expected size of binary to be 70000, got %d", bin_size) + } + + bin_value := Deserialize(data_bytes) + if reflect.TypeOf(bin_value).Kind() != reflect.Slice { + t.Errorf("Expected type of binary to be slice, got %v", reflect.TypeOf(bin_value).Kind()) + } + if !reflect.DeepEqual(bin_value, arr) { + t.Errorf("Expected binary to be %v, got %v", arr, bin_value) + } + + }) + + t.Run("test serialize and deserialize with empty binary", func(t *testing.T) { + arr := make([]byte, 1) + data_bytes := Serialize(arr) + bin_type := data_bytes[0] + + if bin_type != 196 { + t.Errorf("Expected type of binary to be 196 (binary8), got %d", bin_type) + } + + bin_size := int(data_bytes[1]) + if bin_size != 1 { + t.Errorf("Expected size of binary to be 1, got %d", bin_size) + } + + bin_value := Deserialize(data_bytes) + if reflect.TypeOf(bin_value).Kind() != reflect.Slice { + t.Errorf("Expected type of binary to be slice, got %v", reflect.TypeOf(bin_value).Kind()) + } + + bin := bin_value.([]byte) + if bin[0] != 0 { + t.Errorf("Expected binary element to be 0, got %v", bin[0]) + } + + }) +} + +func TestMap(t *testing.T) { + t.Run("test serialize and deserialize with map16", func(t *testing.T) { + m := make(map[any]any) + m["Lang"] = "Go" + m["Ver"] = "1.19" + data_bytes := Serialize(m) + + map_type := data_bytes[0] + if map_type != 222 { + t.Errorf("Expected type of map to be 222 (map16), got %d", map_type) + } + + map_size := decodeSize(data_bytes[1:3]) + if map_size != 2 { + t.Errorf("Expected size of map to be 2, got %d", map_size) + } + + map_value := Deserialize(data_bytes) + if reflect.TypeOf(map_value).Kind() != reflect.Map { + t.Errorf("Expected type of map to be map, got %v", reflect.TypeOf(map_value).Kind()) + } + + if !reflect.DeepEqual(map_value, m) { + t.Errorf("Expected map to be %v, got %v", m, map_value) + } + }) + + t.Run("test serialize and deserialize with map32", func(t *testing.T) { + m := make(map[any]any, 70000) + for i := 0; i < 70000; i++ { + m[fmt.Sprintf("k%d", i)] = fmt.Sprintf("v%d", i) + } + data_bytes := Serialize(m) + + map_type := data_bytes[0] + if map_type != 223 { + t.Errorf("Expected type of map to be 223 (map32), got %d", map_type) + } + + map_size := decodeSize(data_bytes[1:5]) + if map_size != 70000 { + t.Errorf("Expected size of map to be 70000, got %d", map_size) + } + + map_value := Deserialize(data_bytes) + if reflect.TypeOf(map_value).Kind() != reflect.Map { + t.Errorf("Expected type of map to be map, got %v", reflect.TypeOf(map_value).Kind()) + } + + if !reflect.DeepEqual(map_value, m) { + t.Errorf("Expected map to be %v, got %v", m, map_value) + } + }) + + t.Run("test serialize and deserialize with empty map", func(t *testing.T) { + m := make(map[any]any) + data_bytes := Serialize(m) + + map_type := data_bytes[0] + if map_type != 222 { + t.Errorf("Expected type of map to be 222 (map16), got %d", map_type) + } + + map_size := decodeSize(data_bytes[1:3]) + if map_size != 0 { + t.Errorf("Expected size of map to be 0, got %d", map_size) + } + + map_value := Deserialize(data_bytes) + if reflect.TypeOf(map_value).Kind() != reflect.Map { + t.Errorf("Expected type of map to be map, got %v", reflect.TypeOf(map_value).Kind()) + } + + if !reflect.DeepEqual(map_value, m) { + t.Errorf("Expected map to be %v, got %v", m, map_value) + } + }) +} + +func TestAll(t *testing.T) { + t.Run("test pack and unpack with simple struct", func(t *testing.T) { + user_to_pack := User{ + Name: "Fatma", + Id: "id_1", + } + packed, err := Pack(user_to_pack) + + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + var user_unpacked User + _, err = Unpack(packed, &user_unpacked) + + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + if !reflect.DeepEqual(user_to_pack, user_unpacked) { + t.Errorf("Expected %v, got %v", user_to_pack, user_unpacked) + } + + }) + + t.Run("test pack and unpack with complex struct", func(t *testing.T) { + arr := make([]float32, 3) + arr[0] = 1.1 + arr[1] = 2.2 + arr[2] = 3.3 + + m := make(map[any]any) + m["hello"] = 10.0 + m["world"] = -20.0 + + obj_to_pack := Object{ + IsObject: true, + Flag: false, + Unum: 0, + Snum: -1000, + Fnum: 3.14, + Str: "Fatma", + Arr: arr, + Mapp: m, + } + + packed, err := Pack(obj_to_pack) + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + var obj_unpacked Object + _, err = Unpack(packed, &obj_unpacked) + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + packed_unpacked, err := Pack(obj_unpacked) + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + if !reflect.DeepEqual(packed, packed_unpacked) { + t.Errorf("Expected %v, got %v", packed, packed_unpacked) + } + + }) + + type ComplexUser struct { + ID uint32 + Name string + Age int8 + Balance float64 + IsActive bool + Tags []any + Metadata map[string]any + } + + t.Run("test pack and unpack with more complex struct", func(t *testing.T) { + user_to_pack := ComplexUser{ + ID: 123456, + Name: "Fatma Ebrahim", + Age: 27, + Balance: 1050.75, + IsActive: true, + Tags: []any{"golang", "backend", "testing"}, + Metadata: map[string]any{ + "country": "Egypt", + "city": "Cairo", + }, + } + + packed, err := Pack(user_to_pack) + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + var user_unpacked ComplexUser + _, err = Unpack(packed, &user_unpacked) + if err != nil { + t.Errorf("Expected nil, got %v", err) + } + + if !reflect.DeepEqual(user_to_pack, user_unpacked) { + t.Errorf("Expected %+v, got %+v", user_to_pack, user_unpacked) + } + }) +}