1 module tagion.mobile.DocumentWrapperApi; 2 3 import tagion.hibon.Document; 4 import tagion.hibon.HiBON; 5 import tagion.mobile.Recycle; 6 7 // import tagion.basic.Recycle; 8 // import tagion.gossip.GossipNet; 9 // import tagion.wallet.KeyRecover; 10 import tagion.crypto.SecureNet : StdHashNet; 11 12 // import tagion.wallet.KeyRecover; 13 14 import core.runtime : rt_init, rt_term; 15 import core.stdc.stdlib; 16 import std.stdint; 17 import std.string : fromStringz, toStringz; 18 import tagion.basic.Types : Buffer; 19 import tagion.hibon.HiBONJSON; 20 21 public static Recycle!Document recyclerDoc; 22 23 enum BAD_RESULT = 0; 24 25 string[] parse_string(const char* str, const uint len) { 26 string[] result; 27 return result; 28 } 29 30 /// Functions called from d-lang through dart:ffi 31 extern (C) { 32 33 /// Creating Document by ubyte array 34 export uint32_t create_test_doc() { 35 HiBON hibon = new HiBON(); 36 HiBON inner_hibon = new HiBON(); 37 HiBON arr_hibon = new HiBON(); 38 hibon["teststr"] = "test string"; 39 hibon["testnum"] = 123; 40 hibon["testpk"] = cast(Buffer)[1, 1, 1, 1]; 41 const testarr = ["first", "second", "third"]; 42 foreach (i, a; testarr) { 43 arr_hibon[i] = a; 44 } 45 hibon["testarr"] = Document(arr_hibon); 46 inner_hibon["teststr"] = "inner test string"; 47 hibon["inner"] = Document(inner_hibon); 48 auto doc = Document(hibon); 49 if (doc.isInorder()) { 50 auto docId = recyclerDoc.create(doc); 51 return docId; 52 } 53 return BAD_RESULT; 54 } 55 /// Creating Document by ubyte array 56 export uint32_t create_doc(const uint8_t* data_ptr, const uint32_t len) { 57 immutable(ubyte)[] data = cast(immutable(ubyte)[]) data_ptr[0 .. len]; 58 auto doc = Document(data); 59 if (doc.isInorder()) { 60 auto docId = recyclerDoc.create(doc); 61 return docId; 62 } 63 return BAD_RESULT; 64 } 65 66 /// Deleting the specific Document 67 export void delete_doc_by_id(const uint32_t id) { 68 if (id !is BAD_RESULT) { 69 recyclerDoc.erase(id); 70 } 71 } 72 73 /// Getting the int value from Document by integer index 74 export int32_t doc_get_int_by_id(const uint32_t doc_id, const uint32_t index) { 75 if (recyclerDoc(doc_id).hasMember(index)) { 76 return recyclerDoc(doc_id)[index].get!int; 77 } 78 return BAD_RESULT; 79 } 80 81 /// Getting the int value from Document by string key 82 export int32_t doc_get_int_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 83 immutable key = cast(immutable)(key_str[0 .. len]); 84 if (recyclerDoc(doc_id).hasMember(key)) { 85 return recyclerDoc(doc_id)[key].get!int; 86 } 87 return BAD_RESULT; 88 } 89 /// Getting the ulong value from Document by string key 90 export int64_t doc_get_ulong_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 91 immutable key = cast(immutable)(key_str[0 .. len]); 92 if (recyclerDoc(doc_id).hasMember(key)) { 93 return recyclerDoc(doc_id)[key].get!ulong; 94 } 95 return BAD_RESULT; 96 } 97 /// Getting the string value from Document by index 98 /// It uses UF-16 codding 99 export const(char*) doc_get_str_by_id(const uint32_t doc_id, const uint32_t index) { 100 if (recyclerDoc(doc_id).hasMember(index)) { 101 string str = recyclerDoc(doc_id)[index].get!string; 102 return toStringz(str); 103 } 104 return null; 105 } 106 107 /// getting the string value from Document by string key 108 /// It uses UF-16 codding 109 export const(char*) doc_get_str_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 110 immutable key = cast(immutable)(key_str[0 .. len]); 111 if (recyclerDoc(doc_id).hasMember(key)) { 112 string str = recyclerDoc(doc_id)[key].get!string; 113 return toStringz(str); 114 } 115 return null; 116 } 117 118 /// return doc as json 119 /// It uses UF-16 codding 120 export const(char*) doc_as_json(const uint32_t doc_id) { 121 auto doc = recyclerDoc(doc_id); 122 const json = doc.toJSON.toString(); 123 return toStringz(json); 124 } 125 126 /// Getting the Document value from Document by index 127 /// It uses UF-16 codding 128 export uint64_t doc_get_docLen_by_id(const uint32_t doc_id, const uint32_t index) { 129 if (recyclerDoc(doc_id).hasMember(index)) { 130 const doc = recyclerDoc(doc_id)[index].get!Document; 131 return doc.serialize.length; 132 } 133 return BAD_RESULT; 134 } 135 136 /// getting the Document value from Document by string key 137 /// It uses UF-16 codding 138 export uint64_t doc_get_docLen_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 139 immutable key = cast(immutable)(key_str[0 .. len]); 140 if (recyclerDoc(doc_id).hasMember(key)) { 141 const doc = recyclerDoc(doc_id)[key].get!Document; 142 return doc.serialize.length; 143 } 144 return BAD_RESULT; 145 } 146 147 /// Getting the Document value from Document by index 148 /// It uses UF-16 codding 149 export uint8_t* doc_get_docPtr_by_id(const uint32_t doc_id, const uint32_t index) { 150 if (recyclerDoc(doc_id).hasMember(index)) { 151 const doc = recyclerDoc(doc_id)[index].get!Document; 152 return cast(ubyte*) doc.serialize.ptr; 153 } 154 return null; 155 } 156 157 /// getting the Document value from Document by string key 158 /// It uses UF-16 codding 159 export uint8_t* doc_get_docPtr_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 160 immutable key = cast(immutable)(key_str[0 .. len]); 161 if (recyclerDoc(doc_id).hasMember(key)) { 162 const doc = recyclerDoc(doc_id)[key].get!Document; 163 return cast(ubyte*) doc.serialize.ptr; 164 } 165 return null; 166 } 167 168 /// getting the Document value 169 /// It uses UF-16 codding 170 export uint64_t get_docLen(const uint32_t doc_id) { 171 const doc = recyclerDoc(doc_id); 172 return doc.serialize.length; 173 } 174 175 /// getting the Document value 176 /// It uses UF-16 codding 177 export uint8_t* get_docPtr(const uint32_t doc_id) { 178 const doc = recyclerDoc(doc_id); 179 return cast(ubyte*) doc.serialize.ptr; 180 } 181 182 export uint64_t doc_get_bufferLen_by_id(const uint32_t doc_id, const uint32_t index) { 183 if (recyclerDoc(doc_id).hasMember(index)) { 184 const buf = recyclerDoc(doc_id)[index].get!Buffer; 185 return buf.length; 186 } 187 return BAD_RESULT; 188 } 189 190 export uint64_t doc_get_bufferLen_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 191 immutable key = cast(immutable)(key_str[0 .. len]); 192 if (recyclerDoc(doc_id).hasMember(key)) { 193 const buf = recyclerDoc(doc_id)[key].get!Buffer; 194 return buf.length; 195 } 196 return BAD_RESULT; 197 } 198 199 export uint8_t* doc_get_bufferPtr_by_id(const uint32_t doc_id, const uint32_t index) { 200 if (recyclerDoc(doc_id).hasMember(index)) { 201 const doc = recyclerDoc(doc_id)[index].get!Buffer; 202 return cast(ubyte*) doc.ptr; 203 } 204 return null; 205 } 206 207 export uint8_t* doc_get_bufferPtr_by_key(const uint32_t doc_id, const char* key_str, const uint32_t len) { 208 immutable key = cast(immutable)(key_str[0 .. len]); 209 if (recyclerDoc(doc_id).hasMember(key)) { 210 const doc = recyclerDoc(doc_id)[key].get!Buffer; 211 return cast(ubyte*) doc.ptr; 212 } 213 return null; 214 } 215 216 export uint64_t doc_get_memberCount(const uint32_t doc_id) { 217 return recyclerDoc(doc_id).length; 218 } 219 // /// Getting the keys of Document 220 // /// It uses UF-16 codding 221 // export const(char*) doc_get_keys(const uint32_t doc_id) 222 // { 223 // if (recyclerDoc.exists(doc_id)) 224 // { 225 // string[] keys = recyclerDoc(doc_id).keys(); 226 // string keysStr = join(keys, ";"); 227 // return toStringz(keysStr); 228 // } 229 // return null; 230 // } 231 } 232 233 pragma(msg, "fixme(cbr): This unittest does not pass"); 234 version (none) unittest { 235 pragma(msg, "fixme(cbr): Fix this unittest "); 236 import std.stdio : writefln, writeln; 237 import std.string : fromStringz; 238 import tagion.hibon.HiBON : HiBON; 239 240 // Aux HiBON for testing 241 auto hib = new HiBON; 242 hib["doc2"] = "test_str_with_key"; 243 244 // Tests for create_doc() 245 { 246 // Test for null request 247 assert(create_doc(null, 0) is 1); 248 249 // Test for empty array 250 const(ubyte)[] empty_data = new ubyte[0]; 251 assert(create_doc(empty_data.ptr, 0) is 2); 252 253 // Tests for ubytes' sequence 254 // const data1 = hib.serialize; 255 // const data2 = hib.serialize; 256 257 // const doc_id_data_1 = create_doc(data1.ptr, cast(uint)data1.length); 258 // const doc_id_data_2 = create_doc(data2.ptr, cast(uint)data2.length); 259 260 // writefln("doc_id_data_1=%d", doc_id_data_1); 261 // writefln("doc_id_data_2=%d", doc_id_data_2); 262 //assert(create_doc(data1.ptr, data1.length) is 2); 263 //assert(create_doc(data2.ptr, data2.length) is 3); 264 } 265 266 // Tests for delete_doc_by_id() 267 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 268 version (none) { 269 270 assert(recyclerDoc.exists(1)); 271 assert(recyclerDoc.exists(2)); 272 273 delete_doc_by_id(1); 274 delete_doc_by_id(2); 275 276 assert(!recyclerDoc.exists(1)); 277 assert(!recyclerDoc.exists(2)); 278 279 // Append two docs and check whether they exists by indicies 280 const data = hib.serialize; 281 const doc_id_data_a = create_doc(data.ptr, cast(uint) data.length); 282 writefln("doc_id_0=%d", doc_id_data_a); 283 assert(recyclerDoc.exists(doc_id_data_a)); 284 285 const doc_id_data_b = create_doc(data.ptr, cast(uint) data.length); 286 writefln("doc_id_1=%d", doc_id_data_b); 287 assert(recyclerDoc.exists(doc_id_data_b)); 288 } 289 // Range of Document' indexes in RecyclerDoc [0 .. 3] 290 291 // Tests for doc_get_int_by_key() 292 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 293 version (none) { 294 295 assert(doc_get_int_by_key(0, "doc1", 4) is 100); 296 assert(doc_get_int_by_key(1, "doc1", 4) is 100); 297 assert(doc_get_int_by_key(2, "doc1", 4) is 100); 298 assert(doc_get_int_by_key(3, "doc1", 4) is 100); 299 300 // Testing an absense of the key 301 assert(doc_get_int_by_key(0, "doc", 3) is BAD_RESULT); 302 assert(doc_get_int_by_key(1, "doc", 3) is BAD_RESULT); 303 assert(doc_get_int_by_key(2, "doc", 3) is BAD_RESULT); 304 assert(doc_get_int_by_key(3, "doc", 3) is BAD_RESULT); 305 306 // Testing a wrong key size with correct key 307 assert(doc_get_int_by_key(0, "doc1", 3) is BAD_RESULT); 308 assert(doc_get_int_by_key(1, "doc1", 3) is BAD_RESULT); 309 assert(doc_get_int_by_key(2, "doc1", 3) is BAD_RESULT); 310 assert(doc_get_int_by_key(3, "doc1", 3) is BAD_RESULT); 311 312 // Testing a wrong key size with incorrect key 313 assert(doc_get_int_by_key(0, "doc", 10) is BAD_RESULT); 314 assert(doc_get_int_by_key(1, "doc", 10) is BAD_RESULT); 315 assert(doc_get_int_by_key(2, "doc", 10) is BAD_RESULT); 316 assert(doc_get_int_by_key(3, "doc", 10) is BAD_RESULT); 317 } 318 319 // Tests for doc_get_int_by_id() 320 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 321 version (none) { 322 assert(doc_get_int_by_id(0, 1) is 101); 323 assert(doc_get_int_by_id(1, 1) is 101); 324 assert(doc_get_int_by_id(2, 1) is 101); 325 assert(doc_get_int_by_id(3, 1) is 101); 326 327 // Testing an absense of the key 328 assert(doc_get_int_by_id(0, 3) is BAD_RESULT); 329 assert(doc_get_int_by_id(1, 3) is BAD_RESULT); 330 assert(doc_get_int_by_id(2, 3) is BAD_RESULT); 331 assert(doc_get_int_by_id(3, 3) is BAD_RESULT); 332 } 333 334 // Tests for doc_get_str_by_id() 335 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 336 version (none) { 337 const(char)[] expected_str = "test_str_with_id"; 338 339 assert(fromStringz(doc_get_str_by_id(0, 2)) == expected_str); 340 assert(fromStringz(doc_get_str_by_id(1, 2)) == expected_str); 341 assert(fromStringz(doc_get_str_by_id(2, 2)) == expected_str); 342 assert(fromStringz(doc_get_str_by_id(3, 2)) == expected_str); 343 344 // Testing an existed document with wrong id 345 assert(doc_get_str_by_id(0, 0) is null); 346 assert(doc_get_str_by_id(1, 0) is null); 347 assert(doc_get_str_by_id(2, 0) is null); 348 assert(doc_get_str_by_id(3, 0) is null); 349 } 350 351 // Tests for doc_get_str_by_key() 352 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 353 version (none) { 354 const(char)[] expected_str = "test_str_with_key"; 355 356 assert(fromStringz(doc_get_str_by_key(0, "doc2", 4)) == expected_str); 357 assert(fromStringz(doc_get_str_by_key(1, "doc2", 4)) == expected_str); 358 assert(fromStringz(doc_get_str_by_key(2, "doc2", 4)) == expected_str); 359 assert(fromStringz(doc_get_str_by_key(3, "doc2", 4)) == expected_str); 360 361 // Testing an absense of the key 362 assert(doc_get_str_by_key(0, "doc", 3) is null); 363 assert(doc_get_str_by_key(1, "doc", 3) is null); 364 assert(doc_get_str_by_key(2, "doc", 3) is null); 365 assert(doc_get_str_by_key(3, "doc", 3) is null); 366 367 // Testing a wrong key's size with correct key 368 assert(doc_get_str_by_key(0, "doc2", 3) is null); 369 assert(doc_get_str_by_key(1, "doc2", 3) is null); 370 assert(doc_get_str_by_key(2, "doc2", 3) is null); 371 assert(doc_get_str_by_key(3, "doc2", 3) is null); 372 373 // Testing a wrong key's size with incorrect key 374 assert(doc_get_str_by_key(0, "doc", 10) is null); 375 assert(doc_get_str_by_key(1, "doc", 10) is null); 376 assert(doc_get_str_by_key(2, "doc", 10) is null); 377 assert(doc_get_str_by_key(3, "doc", 10) is null); 378 } 379 380 pragma(msg, "fixme(cbr): This unittest does not pass (", __FILE__, ":", __LINE__, ")"); 381 version (none) { 382 import std.algorithm; 383 384 auto hib1 = new HiBON; 385 hib1["test"] = "test"; 386 hib["doc3"] = Document(hib1); 387 const expected = hib1.serialize; 388 389 const data = hib.serialize; 390 auto index = create_doc(data.ptr, cast(uint) data.length); 391 392 const docLen = doc_get_docLen_by_key(index, "test", 4); 393 immutable docPtr = cast(immutable) doc_get_docPtr_by_key(index, "test", 4); 394 const doc = Document(docPtr[0 .. cast(uint) docLen]); 395 assert(equal(expected, doc.serialize)); 396 } 397 }