1 /******************************************************************************* 2 * Main library import for dproto 3 * 4 * Provides accessors for D string and D structs from proto files/data 5 * 6 * Authors: Matthew Soucy, msoucy@csh.rit.edu 7 * Date: Oct 5, 2013 8 * Version: 0.0.2 9 */ 10 module dproto.dproto; 11 12 import std.exception : enforce; 13 14 /******************************************************************************* 15 * Create D structures from proto file 16 * 17 * Creates all required structs given a valid proto file 18 * 19 * Assumes that the file can be found in the string imports 20 */ 21 template ProtocolBuffer(string s) 22 { 23 import dproto.buffers; 24 import dproto.exception; 25 import dproto.serialize; 26 import dproto.parse; 27 mixin(ParseProtoSchema(s,import(s)).toD()); 28 } 29 30 /******************************************************************************* 31 * Create D structure strings from proto data 32 * 33 * Creates all required structs given a valid proto definition as a string 34 */ 35 template ProtocolBufferFromString(string s) 36 { 37 import dproto.buffers; 38 import dproto.exception; 39 import dproto.serialize; 40 import dproto.parse; 41 mixin(ParseProtoSchema("<none>",s).toD()); 42 } 43 44 unittest 45 { 46 assert(__traits(compiles,ProtocolBufferFromString!"message Test 47 { 48 optional string verySimple = 1; 49 }")); 50 } 51 52 unittest 53 { 54 assert(__traits(compiles, ProtocolBufferFromString!" 55 message Test 56 { 57 optional string verySimple = 1; 58 enum TestEnum 59 { 60 ONE = 1; 61 UNO = 1; 62 TOW = 2; 63 } 64 }")); 65 } 66 67 unittest 68 { 69 mixin ProtocolBufferFromString!" 70 message Test 71 { 72 required int32 id = 1; 73 optional string verySimple = 2; 74 enum TestEnum 75 { 76 ONE = 1; 77 UNO = 1; 78 TOW = 2; 79 } 80 optional TestEnum testValue = 3; 81 }"; 82 } 83 84 unittest 85 { 86 assert(__traits(compiles, ProtocolBufferFromString!"message Test 87 { 88 optional string verySimple = 1; 89 enum TestEnum 90 { 91 ONE = 1; 92 UNO = 1; 93 TOW = 2; 94 } 95 96 optional string testValue = 2; 97 }")); 98 } 99 100 unittest 101 { 102 assert(__traits(compiles, ProtocolBufferFromString!" 103 message Test 104 { 105 optional string verySimple = 1; 106 message NestedTest 107 { 108 optional string verySimple = 1; 109 } 110 111 optional NestedTest value = 2; 112 }")); 113 } 114 115 unittest 116 { 117 assert(__traits(compiles, ProtocolBufferFromString!" 118 message Test 119 { 120 optional string verySimple = 1; 121 message NestedTest 122 { 123 optional string verySimple2 = 1; 124 } 125 126 optional NestedTest value = 2; 127 }")); 128 } 129 130 unittest 131 { 132 assert(__traits(compiles, ProtocolBufferFromString!" 133 message Test 134 { 135 optional string verySimple = 1; 136 message NestedTest 137 { 138 optional string verySimple = 1; 139 } 140 141 repeated NestedTest value = 2; 142 }")); 143 } 144 145 unittest 146 { 147 assert(__traits(compiles, ProtocolBufferFromString!" 148 message Test 149 { 150 required int32 id = 3; 151 optional string verySimple = 1; 152 message NestedTest 153 { 154 required string verySimple = 1; 155 } 156 157 required NestedTest value = 2; 158 }")); 159 } 160 161 unittest 162 { 163 assert(__traits(compiles, ProtocolBufferFromString!" 164 message Test 165 { 166 required int32 id = 3; 167 optional string verySimple = 1; 168 message NestedTest 169 { 170 required string verySimple = 1; 171 } 172 173 repeated NestedTest value = 2; 174 }")); 175 } 176 177 unittest 178 { 179 assert(__traits(compiles, ProtocolBufferFromString!" 180 message Test 181 { 182 required int32 id = 3; 183 optional string verySimple = 1; 184 message NestedTest 185 { 186 required string verySimple = 1; 187 } 188 189 optional NestedTest value = 2; 190 }")); 191 } 192 193 unittest 194 { 195 assert(__traits(compiles, ProtocolBufferFromString!" 196 message Test 197 { 198 required int32 id = 3; 199 optional string verySimple = 1; 200 message NestedTest 201 { 202 required string verySimple = 1; 203 } 204 205 repeated NestedTest value = 2; 206 }")); 207 } 208 209 unittest 210 { 211 mixin ProtocolBufferFromString!" 212 enum PhoneType { 213 MOBILE = 0; 214 HOME = 0; 215 WORK = 2; 216 } 217 218 message Person { 219 required string name = 1; 220 required int32 id = 2; 221 optional string email = 3; 222 223 message PhoneNumber { 224 required string number = 1; 225 optional PhoneType type = 2 [default = HOME]; 226 } 227 228 repeated PhoneNumber phone = 4; 229 } 230 "; 231 232 Person t; 233 assert(t.name == ""); 234 assert(t.id == 0); 235 assert(t.phone.length == 0); 236 237 t.name = "Max Musterman"; 238 assert(t.name == "Max Musterman"); 239 240 t.id = 3; 241 assert(t.id == 3); 242 243 t.email = "Max.Musterman@example.com"; 244 assert(t.email == "Max.Musterman@example.com"); 245 assert(t.email.exists()); 246 247 Person.PhoneNumber pn1; 248 pn1.number = "0123456789"; 249 assert(pn1.number == "0123456789"); 250 assert(pn1.type == PhoneType.HOME); 251 assert(pn1.type == PhoneType.MOBILE); 252 253 pn1.type = PhoneType.WORK; 254 assert(pn1.type == PhoneType.WORK); 255 assert(pn1.type == 2); 256 assert(pn1.type.exists()); 257 258 t.phone ~= pn1; 259 assert(t.phone[0] == pn1); 260 assert(t.phone.length == 1); 261 262 pn1.type.clean(); 263 assert(pn1.type == PhoneType.HOME); 264 265 t.phone.clean(); 266 assert(t.phone.length == 0); 267 268 t.email.clean(); 269 assert(t.email == ""); 270 } 271 272 //This unittest fails with DMD I don't know how to fix it. In the main function of a Project it works. 273 //Bjarne Leif Bruhn 2013-11-24 274 version(GNU) 275 { 276 unittest 277 { 278 mixin ProtocolBufferFromString!" 279 message Person { 280 required string name = 1; 281 required int32 id = 2; 282 optional string email = 3; 283 284 enum PhoneType { 285 MOBILE = 0; 286 HOME = 0; 287 WORK = 2; 288 } 289 290 message PhoneNumber { 291 required string number = 1; 292 optional PhoneType type = 2 [default = HOME]; 293 } 294 295 repeated PhoneNumber phone = 4; 296 } 297 298 message AddressBook { 299 repeated Person person = 1; 300 } 301 "; 302 303 Person t; 304 assert(t.name == ""); 305 assert(t.id == 0); 306 assert(t.test.length == 0); 307 308 t.name = "Max Musterman"; 309 assert(t.name == "Max Musterman"); 310 311 t.id = 3; 312 assert(t.id == 3); 313 314 t.email = "Max.Musterman@example.com"; 315 assert(t.email == "Max.Musterman@example.com"); 316 assert(t.email.exists()); 317 318 Person.PhoneNumber pn1; 319 pn1.number = "0123456789"; 320 assert(pn1.number == "0123456789"); 321 322 t.test ~= pn1; 323 assert(t.test[0] == pn1); 324 assert(t.test.length == 1); 325 326 t.test.clean(); 327 assert(t.test.length == 0); 328 329 t.email.clean(); 330 assert(t.email == ""); 331 332 AddressBook addressbook; 333 assert(addressbook.person.length == 0); 334 addressbook.person ~= t; 335 addressbook.person ~= t; 336 assert(addressbook.person[0] == t); 337 assert(addressbook.person[0] == addressbook.person[1]); 338 assert(addressbook.person.length == 2); 339 } 340 341 unittest 342 { 343 mixin ProtocolBufferFromString!" 344 enum PhoneType { 345 MOBILE = 0; 346 HOME = 0; 347 WORK = 2; 348 } 349 350 message Person { 351 required string name = 1; 352 required int32 id = 2; 353 optional string email = 3; 354 355 message PhoneNumber { 356 required string number = 1; 357 optional PhoneType type = 2 [default = HOME]; 358 } 359 360 repeated PhoneNumber phone = 4; 361 } 362 363 message AddressBook { 364 repeated Person person = 1; 365 } 366 "; 367 368 Person t; 369 t.name = "Max Musterman"; 370 t.id = 3; 371 t.email = "test@example.com"; 372 373 Person.PhoneNumber pn1; 374 pn1.number = "0123456789"; 375 pn1.type = PhoneType.WORK; 376 377 Person.PhoneNumber pn2; 378 pn2.number = "0123456789"; 379 380 t.phone = [pn1, pn2]; 381 AddressBook addressbook; 382 addressbook.person ~= t; 383 addressbook.person ~= t; 384 385 ubyte[] serializedObject = addressbook.serialize(); 386 387 AddressBook addressbook2 = AddressBook(serializedObject); 388 assert(addressbook2.person.length == 2); 389 foreach (t2; addressbook2.person[0]) 390 { 391 assert(t2.name == "Max Musterman"); 392 assert(t2.id == 3); 393 assert(t2.email == "test@example.com"); 394 assert(t2.email.exists()); 395 assert(t2.phone[0].number == "0123456789"); 396 assert(t2.phone[0].type == PhoneType.WORK); 397 assert(t2.phone[1].number == "0123456789"); 398 assert(t2.phone[1].type == PhoneType.HOME); 399 assert(t2.phone[1].type == PhoneType.MOBILE); 400 assert(t2.phone.length == 2); 401 } 402 //the gdc-4.8 evaluates false here. Maybe an compiler bug. 403 version(DigitalMars) 404 { 405 assert(addressbook2.person[0] == addressbook.person[1]); 406 } 407 } 408 409 unittest 410 { 411 mixin ProtocolBufferFromString!" 412 message Person { 413 required string name = 1; 414 required int32 id = 2; 415 optional string email = 3; 416 417 enum PhoneType { 418 MOBILE = 0; 419 HOME = 0; 420 WORK = 2; 421 } 422 423 message PhoneNumber { 424 required string number = 1; 425 optional PhoneType type = 2 [default = HOME]; 426 } 427 428 repeated PhoneNumber phone = 4; 429 } 430 431 message AddressBook { 432 repeated Person person = 1; 433 } 434 "; 435 436 Person t; 437 assert(t.name == ""); 438 assert(t.id == 0); 439 assert(t.phone.length == 0); 440 441 t.name = "Max Musterman"; 442 assert(t.name == "Max Musterman"); 443 444 t.id = 3; 445 assert(t.id == 3); 446 447 t.email = "Max.Musterman@example.com"; 448 assert(t.email == "Max.Musterman@example.com"); 449 assert(t.email.exists()); 450 451 Person.PhoneNumber pn1; 452 pn1.number = "0123456789"; 453 assert(pn1.number == "0123456789"); 454 assert(pn1.type == Person.PhoneType.HOME); 455 assert(pn1.type == Person.PhoneType.MOBILE); 456 457 pn1.type = Person.PhoneType.WORK; 458 assert(pn1.type == Person.PhoneType.WORK); 459 assert(pn1.type == 2); 460 assert(pn1.type.exists()); 461 462 t.phone ~= pn1; 463 assert(t.phone[0] == pn1); 464 assert(t.phone.length == 1); 465 466 pn1.type.clean(); 467 assert(pn1.type == Person.PhoneType.HOME); 468 469 t.phone.clean(); 470 assert(t.phone.length == 0); 471 472 t.email.clean(); 473 assert(t.email == ""); 474 475 AddressBook addressbook; 476 assert(addressbook.person.length == 0); 477 addressbook.person ~= t; 478 addressbook.person ~= t; 479 assert(addressbook.person[0] == t); 480 assert(addressbook.person[0] == addressbook.person[1]); 481 assert(addressbook.person.length == 2); 482 } 483 }