From 7142834d3d2e39fbc1c6e51d8652d7b05a77428c Mon Sep 17 00:00:00 2001 From: helintongh Date: Sat, 17 Dec 2022 20:58:52 +0800 Subject: [PATCH 1/2] [cross language demo]go language deserialize demo File use: simple_serialize.cpp will serialize struct person and create a file which content is serialized string and it's name is example.txt.It also a demo which deserialize string to c language. go_deserialize.go is a demo that reads this file(example.txt) , which deserializes the string assignment into the struct. --- .../examples/serialize/CMakeLists.txt | 3 +- .../examples/serialize/go_deserialize.go | 36 ++++++++ .../examples/serialize/simple_serialize.cpp | 88 +++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/struct_pack/examples/serialize/go_deserialize.go create mode 100644 src/struct_pack/examples/serialize/simple_serialize.cpp diff --git a/src/struct_pack/examples/serialize/CMakeLists.txt b/src/struct_pack/examples/serialize/CMakeLists.txt index 1f35551c0..a1c3fd7c3 100644 --- a/src/struct_pack/examples/serialize/CMakeLists.txt +++ b/src/struct_pack/examples/serialize/CMakeLists.txt @@ -1 +1,2 @@ -add_executable(serialize_example serialize.cpp) \ No newline at end of file +add_executable(serialize_example serialize.cpp) +add_executable(cross_language_demo simple_serialize.cpp) \ No newline at end of file diff --git a/src/struct_pack/examples/serialize/go_deserialize.go b/src/struct_pack/examples/serialize/go_deserialize.go new file mode 100644 index 000000000..0531119a2 --- /dev/null +++ b/src/struct_pack/examples/serialize/go_deserialize.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "io/ioutil" + "encoding/binary" +) + +type Person struct { + age uint32 + name string +} + +func deserialize_person(src []byte) Person { + var person Person + person.age = binary.LittleEndian.Uint32(src[4:]) // when computer is big-end there will be error + name_size := src[8] + person.name = string(src[9: 9 + name_size]) + return person +} + + +func main() { + fileName := "../../../../build/examples/example.txt" + data, err := ioutil.ReadFile(fileName); + if err != nil { + fmt.Println("Read file err, err = ", err) + return + } + + de_person := deserialize_person(data) + + fmt.Println("person age is: ", de_person.age) + fmt.Println("person name is: ", de_person.name) + +} \ No newline at end of file diff --git a/src/struct_pack/examples/serialize/simple_serialize.cpp b/src/struct_pack/examples/serialize/simple_serialize.cpp new file mode 100644 index 000000000..8b49d7daf --- /dev/null +++ b/src/struct_pack/examples/serialize/simple_serialize.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "struct_pack/struct_pack.hpp" +#include "struct_pack/struct_pack/struct_pack_impl.hpp" + +// read u32 from binary +static uint32_t deserialize_to_u32(const uint8_t bytes[4]) +{ + return ((bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]); + +} + +// read u64 from binary, no use in this file. +static uint64_t deserialize_to_u64(const uint8_t m[8]) +{ + return ((uint64_t)m[7] << 56) | ((uint64_t)m[6] << 48) | ((uint64_t)m[5] << 40) | ((uint64_t)m[4] << 32) + | ((uint64_t)m[3] << 24) | ((uint64_t)m[2] << 16) | ((uint64_t)m[1] << 8) | ((uint64_t)m[0] << 0); +} + +struct person { + int age; + std::string name; +}; + +int main() +{ + person p{.age = 21, .name = "Betty"}; + std::string buffer = struct_pack::serialize(p); + + std::cout << typeid(buffer).name() << std::endl; + for (int i = 0; i < buffer.size(); i++) + std::cout << buffer[i] << std::endl; + + std::fstream file; + file.open("./example.txt", std::ios::out | std::ios::binary); + + file << buffer; + + file.close(); + + // c deserialize demo + // read serialize string and print deserialize's value + uint8_t *text = (uint8_t*)malloc(128); + FILE *fp = NULL; + fp = fopen("./example.txt", "r"); + fgets((char*)text, 128, fp); + // must be 14 bytes + for (int i = 0; i < 14; i++) + printf("%02x\n", text[i]); + + fclose(fp); + int offset = 4; // first 4 bytes are hash code, no use for other language + int age = deserialize_to_u32(text + offset); + std::cout << "deserialize get age field: " << age << std::endl; + offset += 4; + // only one byte, maxsize string size is 255 + uint8_t string_length = text[offset]; + offset += 1; + char *name = (char*)malloc(string_length); + memcpy(name, (char*)(text + offset), string_length); + std::cout << "deserialize get name field: " << name << std::endl; + + free(text); + free(name); + + return 0; +} From 193fec33abce8022c1c43ae31bd9f1b5a492eb64 Mon Sep 17 00:00:00 2001 From: helintongh Date: Sun, 18 Dec 2022 11:56:54 +0800 Subject: [PATCH 2/2] [cross language demo]go serialized string write to file and cpp read file deserialize to struct go_deserialize will create a file named golang_serialize.txt. read_from_other which source code is deserialize_from_other_language.cpp will read serialized string and deserialize string to cpp struct. the struct person meta json is following: { "hash_code": 2242444774, "struct_name": "person", "fileds": [ { "field_name": "age", "field_type": "int32" }, { "field_name": "name", "field_type": "string" } ] } --- .../examples/serialize/CMakeLists.txt | 3 +- .../deserialize_from_other_language.cpp | 34 ++++++++++++ .../examples/serialize/go_deserialize.go | 52 +++++++++++++++++-- .../examples/serialize/simple_serialize.cpp | 13 +++-- 4 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 src/struct_pack/examples/serialize/deserialize_from_other_language.cpp diff --git a/src/struct_pack/examples/serialize/CMakeLists.txt b/src/struct_pack/examples/serialize/CMakeLists.txt index a1c3fd7c3..c87ed868b 100644 --- a/src/struct_pack/examples/serialize/CMakeLists.txt +++ b/src/struct_pack/examples/serialize/CMakeLists.txt @@ -1,2 +1,3 @@ add_executable(serialize_example serialize.cpp) -add_executable(cross_language_demo simple_serialize.cpp) \ No newline at end of file +add_executable(cross_language_demo simple_serialize.cpp) +add_executable(read_from_other deserialize_from_other_language.cpp) \ No newline at end of file diff --git a/src/struct_pack/examples/serialize/deserialize_from_other_language.cpp b/src/struct_pack/examples/serialize/deserialize_from_other_language.cpp new file mode 100644 index 000000000..cbf354c03 --- /dev/null +++ b/src/struct_pack/examples/serialize/deserialize_from_other_language.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include + +#include "struct_pack/struct_pack.hpp" +#include "struct_pack/struct_pack/struct_pack_impl.hpp" + +struct person { + int age; + std::string name; +}; + +int main() +{ + std::fstream file; + file.open("./golang_serialize.txt", std::ios::in | std::ios::binary); + std::string buffer; + file >> buffer; + file.close(); + + person p{.age = 21, .name = "Betty"}; + person p2; + [[maybe_unused]] auto ec = struct_pack::deserialize_to(p2, buffer); + assert(ec == struct_pack::errc{}); + assert(p == p2); + + std::cout << p2.age << std::endl; + std::cout << p2.name << std::endl; + + + return 0; +} \ No newline at end of file diff --git a/src/struct_pack/examples/serialize/go_deserialize.go b/src/struct_pack/examples/serialize/go_deserialize.go index 0531119a2..f77d46e1d 100644 --- a/src/struct_pack/examples/serialize/go_deserialize.go +++ b/src/struct_pack/examples/serialize/go_deserialize.go @@ -11,12 +11,40 @@ type Person struct { name string } -func deserialize_person(src []byte) Person { +func deserialize_person(src []byte) (*Person) { var person Person + hash_code := binary.LittleEndian.Uint32(src[0:4]) + if hash_code != 2242444774 { + return nil + } + person.age = binary.LittleEndian.Uint32(src[4:]) // when computer is big-end there will be error name_size := src[8] person.name = string(src[9: 9 + name_size]) - return person + return &person +} + +// In general, computer is little-endian +func serialize_person(person Person) (out []byte) { + var serialize_bytes []byte + var hash_code uint32 + hash_code = 2242444774 + hash_bytes := make([]byte, 4) // hashcode 4 bytes + age_u32_bytes := make([]byte, 4) // uint32 4 bytes + var str_size byte // str size 1 byte + // hash code to bytes + binary.LittleEndian.PutUint32(hash_bytes, hash_code) + serialize_bytes = append(serialize_bytes, hash_bytes[:]...) + // field age to bytes + binary.LittleEndian.PutUint32(age_u32_bytes, person.age) + serialize_bytes = append(serialize_bytes, age_u32_bytes[:]...) + // string size to bytes + str_size = (byte)(len(person.name)) + serialize_bytes = append(serialize_bytes, str_size) + // field name to bytes + serialize_bytes = append(serialize_bytes, ([]byte)(person.name)[:]...) + + return serialize_bytes } @@ -27,10 +55,26 @@ func main() { fmt.Println("Read file err, err = ", err) return } - + // 1. deserialize from example.txt de_person := deserialize_person(data) + fmt.Println("person age is: ", de_person.age) fmt.Println("person name is: ", de_person.name) + // 2. serialize person to bytes + serialize_bytes := serialize_person(*de_person) -} \ No newline at end of file + fmt.Println(serialize_bytes) + // 3. deserialize from serialized bytes + de_person2 := deserialize_person(serialize_bytes) + fmt.Println("person age is: ", de_person2.age) + fmt.Println("person name is: ", de_person2.name) + + // 4. write serialized bytes to file + WritefileName := "../../../../build/examples/golang_serialize.txt" + err = ioutil.WriteFile(WritefileName, serialize_bytes, 0777) + if err != nil { + fmt.Println(err) + } + +} diff --git a/src/struct_pack/examples/serialize/simple_serialize.cpp b/src/struct_pack/examples/serialize/simple_serialize.cpp index 8b49d7daf..321e064a4 100644 --- a/src/struct_pack/examples/serialize/simple_serialize.cpp +++ b/src/struct_pack/examples/serialize/simple_serialize.cpp @@ -24,14 +24,13 @@ #include "struct_pack/struct_pack.hpp" #include "struct_pack/struct_pack/struct_pack_impl.hpp" -// read u32 from binary static uint32_t deserialize_to_u32(const uint8_t bytes[4]) { return ((bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]); } -// read u64 from binary, no use in this file. + static uint64_t deserialize_to_u64(const uint8_t m[8]) { return ((uint64_t)m[7] << 56) | ((uint64_t)m[6] << 48) | ((uint64_t)m[5] << 40) | ((uint64_t)m[4] << 32) @@ -59,17 +58,17 @@ int main() file.close(); - // c deserialize demo + // c deserialize // read serialize string and print deserialize's value uint8_t *text = (uint8_t*)malloc(128); FILE *fp = NULL; fp = fopen("./example.txt", "r"); fgets((char*)text, 128, fp); - // must be 14 bytes - for (int i = 0; i < 14; i++) - printf("%02x\n", text[i]); - fclose(fp); + // test hash code + uint32_t hash_code = deserialize_to_u32(text); + std::cout << "hash code is: " << hash_code << std::endl; + int offset = 4; // first 4 bytes are hash code, no use for other language int age = deserialize_to_u32(text + offset); std::cout << "deserialize get age field: " << age << std::endl;