ADATA is an efficient cross platform serialization library for C/C++, with support for Lua, C#, JavaScript and Java.
Note: JavaScript not test yet.
To build adatac, we need:
Build adatac:
adatac [-I PATH] [-O PATH] [-P PATH] [-G language] [--help]
Let's look at an example first
include = util.vec3;
include = my.game.quest;
namespace = my.game;
item
{
int64 id;
int32 type;
int32 level;
}
player_v1
{
int32 id; //player unique id
string name(30); //player name
int32 age;
util.vec3 pos;
list<item> inventory;
list<my.game.quest> quests; //player's quest list
float32 factor = 1.0;
}
player_v2
{
int32 id; //player unique id
string name(30); //player name
int32 age [delete];
util.vec3 pos;
list<item> inventory;
list<my.game.quest> quests; //player's quest list
float32 factor = 1.0 [delete];
list<int32> friends; //friend id list
}
Unlike other libraries, there is no keyword in adata data struct definition. All structs are names, e.g. the item
in previous sample. This is the only way to define objects. Data struct consist of a name (here item, player_v1 and player_v2) and a list of fields. Each field has a type, a name, and optionally a default value.
Data struct is forward and backwards compatibility. User can use [delete] on a field to mark it as deprecated as in the example above(player_v2), which will prevent the generation of accessors in the generated code, as a way to enforce the field not being used any more. For compatibility, user can add new fields in the schema only at the end of a data struct definition.
In the example above, player_v1 is an old version and player_v2 is new version, between them, diff are:
User can:
if and only if user 1) add new fields only at the end of a data struct definition. 2) remove old fields by mark them [delete] 3) don't change old fields.
Built-in scalar types are:
Built-in non-scalar types:
User can optionally use "(num)" to limit max size of all non-scalar types. User can't change types of fields once they're used.
These will generate the corresponding namespace in C++/C# for all helper code, and tables in Lua. You can use . to specify nested namespaces/tables.
You can include other schemas files in your current one, e.g.:
include = file_path.file_name;
Actually, include is an adl file, adatac using -P arg to find these adl files for include, e.g.:
Write "//" behind a field or single one line.
Attributes may be attached to a declaration, behind a field. These may either have a value or not. Currently, just one: "[delete]".
Assuming you have written a schema using the above language in say player.adl, you've generated a C++ header called player.adl.h(rule: [name].adl.h), you can now start using this in your program by including the header. As noted, this header relies on adata/cpp/adata.hpp, which should be in your include path.
Note: generated C++ code support both C++03 and C++11.
Assuming adatac exe under adata/example/adl, player.adl under adata/example/adl/my/game, quest.adl under adata/example/adl/my/game, vec3.adl under adata/example/adl/util, the adatac command are:
First of all, adata::zero_copy_buffer must be created:
adata::zero_copy_buffer stream;
For serializing data, user need an byte array:
#define ENOUGH_SIZE 4096
uint8_t bytes[ENOUGH_SIZE];
int32_t buf_len = ENOUGH_SIZE;
If user want know how length an object after serialization, using adata::size_of:
// create a player_v1 object
my::game::player_v1 pv1;
// set pv1's value
pv1.id = 152001;
pv1.name = "alex";
pv1.age = 22;
// get the size of serialization(depend on its value, diff value may have diff size)
buf_len = adata::size_of(pv1);
Optionally, user can use this length to dyn create byte array:
uint8_t* bytes = new uint8_t[len];
Then set the bytes to stream:
stream.set_write(bytes, buf_len);
The last step to serialize is:
adata::write(stream, pv1);
if (stream.bad())
{
// some error, print it
std::cerr << stream.message() << std::endl;
std::abort();
}
// serialize success, data already write into bytes
First set read data to stream:
// User can copy bytes to other byte array or create other stream whatever.
stream.set_read(bytes, buf_len);
Create another player_v1 object, will deserialize data to it
my::game::player_v1 pv1_other;
Now deserialize:
adata::read(stream, pv1_other);
if (stream.bad())
{
// some error, print it
std::cerr << stream.message() << std::endl;
std::abort();
}
// deserialize success, pv1_other should equals with pv1
// omit operator== for player_v1
//namespace my{ namespace game{
//bool operator==(player_v1 const& lhs, player_v1 const& rhs){
// ...
//}}}
assert(pv1 == pv1_other);
And size_of pv1_other should also equals with pv1:
assert (adata::size_of(pv1) == adata::size_of(pv1_other));
Either read and write, adata::zero_copy_buffer is not threading-safe. Don't share stream between threads (recommended), or manually wrap it in synchronisation primites.
Creating adata::zero_copy_buffer doesn't using any dyn memory, it is cheap, so feel free to create it.
Assuming you have written a schema using the above language in say player.adl, you've generated a lua script file called player_adl.lua(rule: [name]_adl.lua), you can now start using this in your program by require it. As noted, this script file relies on adata/lua/adata_core.lua, which should be in your lua path.
Note: adatac support lua four version: lua51 lua52 lua53 luajit(v2.0.3). User need set adatac arg to generate it: adatac -Gadt .
Note: right now adata only support embedde lua in to c/cpp and pure luajit.
Assuming adatac exe under adata/example/adl, player.adl under adata/example/adl/my/game, quest.adl under adata/example/adl/my/game, vec3.adl under adata/example/adl/util, the adatac command are:
and you can pack player.adt and quest.adt in one file pack.adt *pack.adt adatac.exe -ppaley.adt -pquest.adt -opack.adt
First in c/cpp, user need include adata's header and call adata::lua::init_adata_corec:
#include <lua.hpp>
#include <adata_corec.hpp>
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
adata::lua::init_adata_corec(L);
// run script ...
}
Then in lua, require adata, player_adl.lua and quest_adl.lua:
local adata = require("adata")
adata.load('play.adt')
adata.load('quest.adt')
--or
--adata.load('pack.adt')
And create stream:
local buf_len = 4096
local stream = adata.new(buf_len)
Don't like cpp, in lua, zero_copy_buffer already have a buffer to write when created.
Now create player_v1 object and set its value to serialize:
-- create a player_v1 object
local pv1 = adata.types['game.player_v1']
-- set its value
pv1.id = 1
pv1.age = 22
pv1.factor = 2.0
pv1.name = "pv1"
local itm = player_adl.item()
itm.id = 11
itm.level = 321110
itm.type = 3
table.insert(pv1.inventory, itm)
itm = player_adl.item()
itm.id = 12
table.insert(pv1.inventory, itm)
local qst = adata.types['game.quest']
qst.id = 50
qst.name = "quest1"
qst.description = "There are something unusual..."
table.insert(pv1.quests, qst)
Then serialize:
pv1:write(stream)
-- serialize success, data already write into stream's write buffer
User can get write data:
-- data actually is a string
local data = stream:get_write_data()
First set read data to stream:
stream:set_read_data(data)
Create another player_v1 object, will deserialize data to it
local pv1_other = adata.types['game.player_v1']
Now deserialize:
pv1_other:read(stream)
-- deserialize success, pv1_other should equals with pv1
Assuming you have written a schema using the above language in say player.adl, you've generated a C# file called player.adl.cs(rule: [name].adl.cs), you can now start using this in your program by adding the file. As noted, this file relies on adata/csharp/adata.cs, which should be added in your project.
Assuming adatac exe under adata/example/adl, player.adl under adata/example/adl/my/game, quest.adl under adata/example/adl/my/game, vec3.adl under adata/example/adl/util, the adatac command are:
First, create adata.zero_copy_buffer:
var bytes = new bytes[4096];
var stream = new adata.ZeroCopyBuffer(bytes);
Now create PlayerV1 object and set its value to serialize:
// create a my.game.player_v1 object
var pv1 = new my.game.PlayerV1();
// set its value
pv1.id = 152001
pv1.name = "alex"
pv1.age = 22
Serialize:
// rule: adata.[adl file name]_stream.stream_write
pv1.Write(stream);
// serialize success
C#'s adata.zero_copy_buffer read and write shared same byte array, so this just use stream to read:
// create other PlayerV1 to deserialize
var pv1_other = new my.game.PlayerV1();
// deserialize
pv1_other.Read(stream);
// deserialize success
pv1's value should equals with pv1_other and size_of also as well.
Assuming you have written a schema using the above language in say player.adl, you've generated a directory with namespace as you defined(rule: my/game/), you can now start using this in your program by adding the file. As noted, this file relies on adata.jar, which should be added in your project.
Assuming adatac exe under adata/example/adl, player.adl under adata/example/adl/my/game, quest.adl under adata/example/adl/my/game, vec3.adl under adata/example/adl/util, the adatac command are:
First, create adata.Stream:
adata.Stream stream = new adata.Stream();
byte[] buf = new byte[4096];
stream.setReadBuffer(buf);```
stream.setWriteBuffer(buf);
Now create player_v1 object and set its value to serialize:
```java
// create a my.game.player_v1 object
my.game.player_v1 pv1 = new my.game.player_v1();
// set its value
pv1.id = 152001
pv1.name = "alex"
pv1.age = 22
//serialize:
pv1.write(stream);
// serialize success
java's adata.Stream read and write shared same byte array, so this just use stream to read:
// create other player_v1 to deserialize
my.game.player_v1 pv1_other = new my.game.player_v1();
// deserialize
pv1_other.read(stream);
// deserialize success
pv1's value should equals with pv1_other and size_of also as well.
JavaScript as same as lua
First, load the .adt file
var Long = require('long');
var adata = require('adata');
var s = new adata();
//callback_fn is the action when file load done.
s.load('./testpack.adt',callback_fn);
var callback_fn = function (){
var playe_v1_type = s.type('my.game.player_v1')
var pv1 = playe_v1_type();
//serialize:
v1.write(s);
//deserialize:
var pv2 = playe_v1_type();
v2.read(s);
}
Change log: *v1.4 1.add buffer type 2.clear c# code compatible c# name rule
*v1.3.1 1.add kotlin suport
*v1.3 1.change C++ error handler to exception 2.change lua error handler to exception 3.add javascript support 4.add "raw" mode on read , write , size_of interface, run fast but no compatibility. 5.remove boost require for compiler. 6.add java support 7.add move error hint
*v1.2 1.remove lua code generate,all lua(5.1,5.2,luajit) and add binary format adt files,lua and javascript use adt file dynamic load schema data type. 2.adt can package some single adt file in one file. usage: adatac.exe -Ppath -pfile1.adt -pfile2.adt -opack.adt
*V 1.1 1.improvement lua implement performance 2.fix bug of lua_int64
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。