]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/d/src/thrift/codegen/idlgen.d
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / lib / d / src / thrift / codegen / idlgen.d
CommitLineData
f67539c2
TL
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/**
21 * Contains <b>experimental</b> functionality for generating Thrift IDL files
22 * (.thrift) from existing D data structures, i.e. the reverse of what the
23 * Thrift compiler does.
24 */
25module thrift.codegen.idlgen;
26
27import std.algorithm : find;
28import std.array : empty, front;
29import std.conv : to;
30import std.traits : EnumMembers, isSomeFunction, OriginalType,
31 ParameterTypeTuple, ReturnType;
32import std.typetuple : allSatisfy, staticIndexOf, staticMap, NoDuplicates,
33 TypeTuple;
34import thrift.base;
35import thrift.codegen.base;
36import thrift.internal.codegen;
37import thrift.internal.ctfe;
38import thrift.util.hashset;
39
40/**
41 * True if the passed type is a Thrift entity (struct, exception, enum,
42 * service).
43 */
44alias Any!(isStruct, isException, isEnum, isService) isThriftEntity;
45
46/**
47 * Returns an IDL string describing the passed »root« entities and all types
48 * they depend on.
49 */
50template idlString(Roots...) if (allSatisfy!(isThriftEntity, Roots)) {
51 enum idlString = idlStringImpl!Roots.result;
52}
53
54private {
55 template idlStringImpl(Roots...) if (allSatisfy!(isThriftEntity, Roots)) {
56 alias ForAllWithList!(
57 ConfinedTuple!(StaticFilter!(isService, Roots)),
58 AddBaseServices
59 ) Services;
60
61 alias TypeTuple!(
62 StaticFilter!(isEnum, Roots),
63 ForAllWithList!(
64 ConfinedTuple!(
65 StaticFilter!(Any!(isException, isStruct), Roots),
66 staticMap!(CompositeTypeDeps, staticMap!(ServiceTypeDeps, Services))
67 ),
68 AddStructWithDeps
69 )
70 ) Types;
71
72 enum result = ctfeJoin(
73 [
74 staticMap!(
75 enumIdlString,
76 StaticFilter!(isEnum, Types)
77 ),
78 staticMap!(
79 structIdlString,
80 StaticFilter!(Any!(isStruct, isException), Types)
81 ),
82 staticMap!(
83 serviceIdlString,
84 Services
85 )
86 ],
87 "\n"
88 );
89 }
90
91 template ServiceTypeDeps(T) if (isService!T) {
92 alias staticMap!(
93 PApply!(MethodTypeDeps, T),
94 FilterMethodNames!(T, __traits(derivedMembers, T))
95 ) ServiceTypeDeps;
96 }
97
98 template MethodTypeDeps(T, string name) if (
99 isService!T && isSomeFunction!(MemberType!(T, name))
100 ) {
101 alias TypeTuple!(
102 ReturnType!(MemberType!(T, name)),
103 ParameterTypeTuple!(MemberType!(T, name)),
104 ExceptionTypes!(T, name)
105 ) MethodTypeDeps;
106 }
107
108 template ExceptionTypes(T, string name) if (
109 isService!T && isSomeFunction!(MemberType!(T, name))
110 ) {
111 mixin({
112 enum meta = find!`a.name == b`(getMethodMeta!T, name);
113 if (meta.empty) return "alias TypeTuple!() ExceptionTypes;";
114
115 string result = "alias TypeTuple!(";
116 foreach (i, e; meta.front.exceptions) {
117 if (i > 0) result ~= ", ";
118 result ~= "mixin(`T." ~ e.type ~ "`)";
119 }
120 result ~= ") ExceptionTypes;";
121 return result;
122 }());
123 }
124
125 template AddBaseServices(T, List...) {
126 static if (staticIndexOf!(T, List) == -1) {
127 alias NoDuplicates!(BaseServices!T, List) AddBaseServices;
128 } else {
129 alias List AddStructWithDeps;
130 }
131 }
132
133 unittest {
134 interface A {}
135 interface B : A {}
136 interface C : B {}
137 interface D : A {}
138
139 static assert(is(AddBaseServices!(C) == TypeTuple!(A, B, C)));
140 static assert(is(ForAllWithList!(ConfinedTuple!(C, D), AddBaseServices) ==
141 TypeTuple!(A, D, B, C)));
142 }
143
144 template BaseServices(T, Rest...) if (isService!T) {
145 static if (isDerivedService!T) {
146 alias BaseServices!(BaseService!T, T, Rest) BaseServices;
147 } else {
148 alias TypeTuple!(T, Rest) BaseServices;
149 }
150 }
151
152 template AddStructWithDeps(T, List...) {
153 static if (staticIndexOf!(T, List) == -1) {
154 // T is not already in the List, so add T and the types it depends on in
155 // the front. Because with the Thrift compiler types can only depend on
156 // other types that have already been defined, we collect all the
157 // dependencies, prepend them to the list, and then prune the duplicates
158 // (keeping the first occurrences). If this requirement should ever be
159 // dropped from Thrift, this could be easily adapted to handle circular
160 // dependencies by passing TypeTuple!(T, List) to ForAllWithList instead
161 // of appending List afterwards, and removing the now unnecessary
162 // NoDuplicates.
163 alias NoDuplicates!(
164 ForAllWithList!(
165 ConfinedTuple!(
166 staticMap!(
167 CompositeTypeDeps,
168 staticMap!(
169 PApply!(MemberType, T),
170 FieldNames!T
171 )
172 )
173 ),
174 .AddStructWithDeps,
175 T
176 ),
177 List
178 ) AddStructWithDeps;
179 } else {
180 alias List AddStructWithDeps;
181 }
182 }
183
184 version (unittest) {
185 struct A {}
186 struct B {
187 A a;
188 int b;
189 A c;
190 string d;
191 }
192 struct C {
193 B b;
194 A a;
195 }
196
197 static assert(is(AddStructWithDeps!C == TypeTuple!(A, B, C)));
198
199 struct D {
200 C c;
201 mixin TStructHelpers!([TFieldMeta("c", 0, TReq.IGNORE)]);
202 }
203 static assert(is(AddStructWithDeps!D == TypeTuple!(D)));
204 }
205
206 version (unittest) {
207 // Circles in the type dependency graph are not allowed in Thrift, but make
208 // sure we fail in a sane way instead of crashing the compiler.
209
210 struct Rec1 {
211 Rec2[] other;
212 }
213
214 struct Rec2 {
215 Rec1[] other;
216 }
217
218 static assert(!__traits(compiles, AddStructWithDeps!Rec1));
219 }
220
221 /*
222 * Returns the non-primitive types T directly depends on.
223 *
224 * For example, CompositeTypeDeps!int would yield an empty type tuple,
225 * CompositeTypeDeps!SomeStruct would give SomeStruct, and
226 * CompositeTypeDeps!(A[B]) both CompositeTypeDeps!A and CompositeTypeDeps!B.
227 */
228 template CompositeTypeDeps(T) {
229 static if (is(FullyUnqual!T == bool) || is(FullyUnqual!T == byte) ||
230 is(FullyUnqual!T == short) || is(FullyUnqual!T == int) ||
231 is(FullyUnqual!T == long) || is(FullyUnqual!T : string) ||
232 is(FullyUnqual!T == double) || is(FullyUnqual!T == void)
233 ) {
234 alias TypeTuple!() CompositeTypeDeps;
235 } else static if (is(FullyUnqual!T _ : U[], U)) {
236 alias CompositeTypeDeps!U CompositeTypeDeps;
237 } else static if (is(FullyUnqual!T _ : HashSet!E, E)) {
238 alias CompositeTypeDeps!E CompositeTypeDeps;
239 } else static if (is(FullyUnqual!T _ : V[K], K, V)) {
240 alias TypeTuple!(CompositeTypeDeps!K, CompositeTypeDeps!V) CompositeTypeDeps;
241 } else static if (is(FullyUnqual!T == enum) || is(FullyUnqual!T == struct) ||
242 is(FullyUnqual!T : TException)
243 ) {
244 alias TypeTuple!(FullyUnqual!T) CompositeTypeDeps;
245 } else {
246 static assert(false, "Cannot represent type in Thrift: " ~ T.stringof);
247 }
248 }
249}
250
251/**
252 * Returns an IDL string describing the passed service. IDL code for any type
253 * dependcies is not included.
254 */
255template serviceIdlString(T) if (isService!T) {
256 enum serviceIdlString = {
257 string result = "service " ~ T.stringof;
258 static if (isDerivedService!T) {
259 result ~= " extends " ~ BaseService!T.stringof;
260 }
261 result ~= " {\n";
262
263 foreach (methodName; FilterMethodNames!(T, __traits(derivedMembers, T))) {
264 result ~= " ";
265
266 enum meta = find!`a.name == b`(T.methodMeta, methodName);
267
268 static if (!meta.empty && meta.front.type == TMethodType.ONEWAY) {
269 result ~= "oneway ";
270 }
271
272 alias ReturnType!(MemberType!(T, methodName)) RT;
273 static if (is(RT == void)) {
274 // We special-case this here instead of adding void to dToIdlType to
275 // avoid accepting things like void[].
276 result ~= "void ";
277 } else {
278 result ~= dToIdlType!RT ~ " ";
279 }
280 result ~= methodName ~ "(";
281
282 short lastId;
283 foreach (i, ParamType; ParameterTypeTuple!(MemberType!(T, methodName))) {
284 static if (!meta.empty && i < meta.front.params.length) {
285 enum havePM = true;
286 } else {
287 enum havePM = false;
288 }
289
290 short id;
291 static if (havePM) {
292 id = meta.front.params[i].id;
293 } else {
294 id = --lastId;
295 }
296
297 string paramName;
298 static if (havePM) {
299 paramName = meta.front.params[i].name;
300 } else {
301 paramName = "param" ~ to!string(i + 1);
302 }
303
304 result ~= to!string(id) ~ ": " ~ dToIdlType!ParamType ~ " " ~ paramName;
305
306 static if (havePM && !meta.front.params[i].defaultValue.empty) {
307 result ~= " = " ~ dToIdlConst(mixin(meta.front.params[i].defaultValue));
308 } else {
309 // Unfortunately, getting the default value for parameters from a
310 // function alias isn't possible – we can't transfer the default
311 // value to the IDL e.g. for interface Foo { void foo(int a = 5); }
312 // without the user explicitly declaring it in metadata.
313 }
314 result ~= ", ";
315 }
316 result ~= ")";
317
318 static if (!meta.empty && !meta.front.exceptions.empty) {
319 result ~= " throws (";
320 foreach (e; meta.front.exceptions) {
321 result ~= to!string(e.id) ~ ": " ~ e.type ~ " " ~ e.name ~ ", ";
322 }
323 result ~= ")";
324 }
325
326 result ~= ",\n";
327 }
328
329 result ~= "}\n";
330 return result;
331 }();
332}
333
334/**
335 * Returns an IDL string describing the passed enum. IDL code for any type
336 * dependcies is not included.
337 */
338template enumIdlString(T) if (isEnum!T) {
339 enum enumIdlString = {
340 static assert(is(OriginalType!T : long),
341 "Can only have integer enums in Thrift (not " ~ OriginalType!T.stringof ~
342 ", for " ~ T.stringof ~ ").");
343
344 string result = "enum " ~ T.stringof ~ " {\n";
345
346 foreach (name; __traits(derivedMembers, T)) {
347 result ~= " " ~ name ~ " = " ~ dToIdlConst(GetMember!(T, name)) ~ ",\n";
348 }
349
350 result ~= "}\n";
351 return result;
352 }();
353}
354
355/**
356 * Returns an IDL string describing the passed struct. IDL code for any type
357 * dependcies is not included.
358 */
359template structIdlString(T) if (isStruct!T || isException!T) {
360 enum structIdlString = {
361 mixin({
362 string code = "";
363 foreach (field; getFieldMeta!T) {
364 code ~= "static assert(is(MemberType!(T, `" ~ field.name ~ "`)));\n";
365 }
366 return code;
367 }());
368
369 string result;
370 static if (isException!T) {
371 result = "exception ";
372 } else {
373 result = "struct ";
374 }
375 result ~= T.stringof ~ " {\n";
376
377 // The last automatically assigned id – fields with no meta information
378 // are assigned (in lexical order) descending negative ids, starting with
379 // -1, just like the Thrift compiler does.
380 short lastId;
381
382 foreach (name; FieldNames!T) {
383 enum meta = find!`a.name == b`(getFieldMeta!T, name);
384
385 static if (meta.empty || meta.front.req != TReq.IGNORE) {
386 short id;
387 static if (meta.empty) {
388 id = --lastId;
389 } else {
390 id = meta.front.id;
391 }
392
393 result ~= " " ~ to!string(id) ~ ":";
394 static if (!meta.empty) {
395 result ~= dToIdlReq(meta.front.req);
396 }
397 result ~= " " ~ dToIdlType!(MemberType!(T, name)) ~ " " ~ name;
398
399 static if (!meta.empty && !meta.front.defaultValue.empty) {
400 result ~= " = " ~ dToIdlConst(mixin(meta.front.defaultValue));
401 } else static if (__traits(compiles, fieldInitA!(T, name))) {
402 static if (is(typeof(fieldInitA!(T, name))) &&
403 !is(typeof(fieldInitA!(T, name)) == void)
404 ) {
405 result ~= " = " ~ dToIdlConst(fieldInitA!(T, name));
406 }
407 } else static if (is(typeof(fieldInitB!(T, name))) &&
408 !is(typeof(fieldInitB!(T, name)) == void)
409 ) {
410 result ~= " = " ~ dToIdlConst(fieldInitB!(T, name));
411 }
412 result ~= ",\n";
413 }
414 }
415
416 result ~= "}\n";
417 return result;
418 }();
419}
420
421private {
422 // This very convoluted way of doing things was chosen because putting the
423 // static if directly into structIdlString caused »not evaluatable at compile
424 // time« errors to slip through even though typeof() was used, resp. the
425 // condition to be true even though the value couldn't actually be read at
426 // compile time due to a @@BUG@@ in DMD 2.055.
427 // The extra »compiled« field in fieldInitA is needed because we must not try
428 // to use != if !is compiled as well (but was false), e.g. for floating point
429 // types.
430 template fieldInitA(T, string name) {
431 static if (mixin("T.init." ~ name) !is MemberType!(T, name).init) {
432 enum fieldInitA = mixin("T.init." ~ name);
433 }
434 }
435
436 template fieldInitB(T, string name) {
437 static if (mixin("T.init." ~ name) != MemberType!(T, name).init) {
438 enum fieldInitB = mixin("T.init." ~ name);
439 }
440 }
441
442 template dToIdlType(T) {
443 static if (is(FullyUnqual!T == bool)) {
444 enum dToIdlType = "bool";
445 } else static if (is(FullyUnqual!T == byte)) {
446 enum dToIdlType = "byte";
447 } else static if (is(FullyUnqual!T == double)) {
448 enum dToIdlType = "double";
449 } else static if (is(FullyUnqual!T == short)) {
450 enum dToIdlType = "i16";
451 } else static if (is(FullyUnqual!T == int)) {
452 enum dToIdlType = "i32";
453 } else static if (is(FullyUnqual!T == long)) {
454 enum dToIdlType = "i64";
455 } else static if (is(FullyUnqual!T : string)) {
456 enum dToIdlType = "string";
457 } else static if (is(FullyUnqual!T _ : U[], U)) {
458 enum dToIdlType = "list<" ~ dToIdlType!U ~ ">";
459 } else static if (is(FullyUnqual!T _ : V[K], K, V)) {
460 enum dToIdlType = "map<" ~ dToIdlType!K ~ ", " ~ dToIdlType!V ~ ">";
461 } else static if (is(FullyUnqual!T _ : HashSet!E, E)) {
462 enum dToIdlType = "set<" ~ dToIdlType!E ~ ">";
463 } else static if (is(FullyUnqual!T == struct) || is(FullyUnqual!T == enum) ||
464 is(FullyUnqual!T : TException)
465 ) {
466 enum dToIdlType = FullyUnqual!(T).stringof;
467 } else {
468 static assert(false, "Cannot represent type in Thrift: " ~ T.stringof);
469 }
470 }
471
472 string dToIdlReq(TReq req) {
473 switch (req) {
474 case TReq.REQUIRED: return " required";
475 case TReq.OPTIONAL: return " optional";
476 default: return "";
477 }
478 }
479
480 string dToIdlConst(T)(T value) {
481 static if (is(FullyUnqual!T == bool)) {
482 return value ? "1" : "0";
483 } else static if (is(FullyUnqual!T == byte) ||
484 is(FullyUnqual!T == short) || is(FullyUnqual!T == int) ||
485 is(FullyUnqual!T == long)
486 ) {
487 return to!string(value);
488 } else static if (is(FullyUnqual!T : string)) {
489 return `"` ~ to!string(value) ~ `"`;
490 } else static if (is(FullyUnqual!T == double)) {
491 return ctfeToString(value);
492 } else static if (is(FullyUnqual!T _ : U[], U) ||
493 is(FullyUnqual!T _ : HashSet!E, E)
494 ) {
495 string result = "[";
496 foreach (e; value) {
497 result ~= dToIdlConst(e) ~ ", ";
498 }
499 result ~= "]";
500 return result;
501 } else static if (is(FullyUnqual!T _ : V[K], K, V)) {
502 string result = "{";
503 foreach (key, val; value) {
504 result ~= dToIdlConst(key) ~ ": " ~ dToIdlConst(val) ~ ", ";
505 }
506 result ~= "}";
507 return result;
508 } else static if (is(FullyUnqual!T == enum)) {
509 import std.conv;
510 import std.traits;
511 return to!string(cast(OriginalType!T)value);
512 } else static if (is(FullyUnqual!T == struct) ||
513 is(FullyUnqual!T : TException)
514 ) {
515 string result = "{";
516 foreach (name; __traits(derivedMembers, T)) {
517 static if (memberReq!(T, name) != TReq.IGNORE) {
518 result ~= name ~ ": " ~ dToIdlConst(mixin("value." ~ name)) ~ ", ";
519 }
520 }
521 result ~= "}";
522 return result;
523 } else {
524 static assert(false, "Cannot represent type in Thrift: " ~ T.stringof);
525 }
526 }
527}
528
529version (unittest) {
530 enum Foo {
531 a = 1,
532 b = 10,
533 c = 5
534 }
535
536 static assert(enumIdlString!Foo ==
537`enum Foo {
538 a = 1,
539 b = 10,
540 c = 5,
541}
542`);
543}
544
545
546version (unittest) {
547 struct WithoutMeta {
548 string a;
549 int b;
550 }
551
552 struct WithDefaults {
553 string a = "asdf";
554 double b = 3.1415;
555 WithoutMeta c;
556
557 mixin TStructHelpers!([
558 TFieldMeta("c", 1, TReq.init, `WithoutMeta("foo", 3)`)
559 ]);
560 }
561
562 // These are from DebugProtoTest.thrift.
563 struct OneOfEach {
564 bool im_true;
565 bool im_false;
566 byte a_bite;
567 short integer16;
568 int integer32;
569 long integer64;
570 double double_precision;
571 string some_characters;
572 string zomg_unicode;
573 bool what_who;
574 string base64;
575 byte[] byte_list;
576 short[] i16_list;
577 long[] i64_list;
578
579 mixin TStructHelpers!([
580 TFieldMeta(`im_true`, 1),
581 TFieldMeta(`im_false`, 2),
582 TFieldMeta(`a_bite`, 3, TReq.OPT_IN_REQ_OUT, q{cast(byte)127}),
583 TFieldMeta(`integer16`, 4, TReq.OPT_IN_REQ_OUT, q{cast(short)32767}),
584 TFieldMeta(`integer32`, 5),
585 TFieldMeta(`integer64`, 6, TReq.OPT_IN_REQ_OUT, q{10000000000L}),
586 TFieldMeta(`double_precision`, 7),
587 TFieldMeta(`some_characters`, 8),
588 TFieldMeta(`zomg_unicode`, 9),
589 TFieldMeta(`what_who`, 10),
590 TFieldMeta(`base64`, 11),
591 TFieldMeta(`byte_list`, 12, TReq.OPT_IN_REQ_OUT, q{{
592 byte[] v;
593 v ~= cast(byte)1;
594 v ~= cast(byte)2;
595 v ~= cast(byte)3;
596 return v;
597 }()}),
598 TFieldMeta(`i16_list`, 13, TReq.OPT_IN_REQ_OUT, q{{
599 short[] v;
600 v ~= cast(short)1;
601 v ~= cast(short)2;
602 v ~= cast(short)3;
603 return v;
604 }()}),
605 TFieldMeta(`i64_list`, 14, TReq.OPT_IN_REQ_OUT, q{{
606 long[] v;
607 v ~= 1L;
608 v ~= 2L;
609 v ~= 3L;
610 return v;
611 }()})
612 ]);
613 }
614
615 struct Bonk {
616 int type;
617 string message;
618
619 mixin TStructHelpers!([
620 TFieldMeta(`type`, 1),
621 TFieldMeta(`message`, 2)
622 ]);
623 }
624
625 struct HolyMoley {
626 OneOfEach[] big;
627 HashSet!(string[]) contain;
628 Bonk[][string] bonks;
629
630 mixin TStructHelpers!([
631 TFieldMeta(`big`, 1),
632 TFieldMeta(`contain`, 2),
633 TFieldMeta(`bonks`, 3)
634 ]);
635 }
636
637 static assert(structIdlString!WithoutMeta ==
638`struct WithoutMeta {
639 -1: string a,
640 -2: i32 b,
641}
642`);
643
644import std.algorithm;
645 static assert(structIdlString!WithDefaults.startsWith(
646`struct WithDefaults {
647 -1: string a = "asdf",
648 -2: double b = 3.141`));
649
650 static assert(structIdlString!WithDefaults.endsWith(
651`1: WithoutMeta c = {a: "foo", b: 3, },
652}
653`));
654
655 static assert(structIdlString!OneOfEach ==
656`struct OneOfEach {
657 1: bool im_true,
658 2: bool im_false,
659 3: byte a_bite = 127,
660 4: i16 integer16 = 32767,
661 5: i32 integer32,
662 6: i64 integer64 = 10000000000,
663 7: double double_precision,
664 8: string some_characters,
665 9: string zomg_unicode,
666 10: bool what_who,
667 11: string base64,
668 12: list<byte> byte_list = [1, 2, 3, ],
669 13: list<i16> i16_list = [1, 2, 3, ],
670 14: list<i64> i64_list = [1, 2, 3, ],
671}
672`);
673
674 static assert(structIdlString!Bonk ==
675`struct Bonk {
676 1: i32 type,
677 2: string message,
678}
679`);
680
681 static assert(structIdlString!HolyMoley ==
682`struct HolyMoley {
683 1: list<OneOfEach> big,
684 2: set<list<string>> contain,
685 3: map<string, list<Bonk>> bonks,
686}
687`);
688}
689
690version (unittest) {
691 class ExceptionWithAMap : TException {
692 string blah;
693 string[string] map_field;
694
695 mixin TStructHelpers!([
696 TFieldMeta(`blah`, 1),
697 TFieldMeta(`map_field`, 2)
698 ]);
699 }
700
701 interface Srv {
702 void voidMethod();
703 int primitiveMethod();
704 OneOfEach structMethod();
705 void methodWithDefaultArgs(int something);
706 void onewayMethod();
707 void exceptionMethod();
708
709 alias .ExceptionWithAMap ExceptionWithAMap;
710
711 enum methodMeta = [
712 TMethodMeta(`methodWithDefaultArgs`,
713 [TParamMeta(`something`, 1, q{2})]
714 ),
715 TMethodMeta(`onewayMethod`,
716 [],
717 [],
718 TMethodType.ONEWAY
719 ),
720 TMethodMeta(`exceptionMethod`,
721 [],
722 [
723 TExceptionMeta("a", 1, "ExceptionWithAMap"),
724 TExceptionMeta("b", 2, "ExceptionWithAMap")
725 ]
726 )
727 ];
728 }
729
730 interface ChildSrv : Srv {
731 int childMethod(int arg);
732 }
733
734 static assert(idlString!ChildSrv ==
735`exception ExceptionWithAMap {
736 1: string blah,
737 2: map<string, string> map_field,
738}
739
740struct OneOfEach {
741 1: bool im_true,
742 2: bool im_false,
743 3: byte a_bite = 127,
744 4: i16 integer16 = 32767,
745 5: i32 integer32,
746 6: i64 integer64 = 10000000000,
747 7: double double_precision,
748 8: string some_characters,
749 9: string zomg_unicode,
750 10: bool what_who,
751 11: string base64,
752 12: list<byte> byte_list = [1, 2, 3, ],
753 13: list<i16> i16_list = [1, 2, 3, ],
754 14: list<i64> i64_list = [1, 2, 3, ],
755}
756
757service Srv {
758 void voidMethod(),
759 i32 primitiveMethod(),
760 OneOfEach structMethod(),
761 void methodWithDefaultArgs(1: i32 something = 2, ),
762 oneway void onewayMethod(),
763 void exceptionMethod() throws (1: ExceptionWithAMap a, 2: ExceptionWithAMap b, ),
764}
765
766service ChildSrv extends Srv {
767 i32 childMethod(-1: i32 param1, ),
768}
769`);
770}