termite-dmg 0.7.0

Termite Data Model Generator is a crate meant to generate boiler plate code for data models.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# Termite Data Model Generator


The Termite Data Model Generator is a crate for generating boiler plate code
for data models.

## Data Model


The crate consists of two parts, the first is the data model itself. This is
preferably imported from a yaml or json file into a DataModel object.

It can also be defined directly in code, however, this is not as readable or
easy to write.

A DataModel object consist of header and footer strings and a list of all the
data types. The header and footer strings are strings to add to the top and
bottom of the generated files like for adding includes in .cpp files. The data
types are names and data for the user defined types defined to be generated by
termite.

The headers and footers are both using the same format. They are maps of strings
with each object in the map referering to the string to add as header/footer for
the file refered to by the key. Currently the only supported keys are
"cpp-header" and "cpp-source" for the generated ".h" and ".cpp" files.

A namespace can be defined as a list of strings defining the nested namespace,
this is only used in c++.

A list of macros can also be defined, these maps a string to a yaml or json
structure (string, map or list). Inside any default value definition or a header
or footer, if any string is encased in dollar signs then the value is used as
the key to find the corresponding macro which is inserted in its place, this
also works recursively. A map or list macro can only be inserted if the macro
definition is the only thing in the header or default value while a string can
be inserted anywhere.

A data type must be given a "name", type specific "data", and optionally a
"description". The type specific data defines how the type is implemented and may
be types like structs, enums or arrays.

The different types are:

Struct: A normal struct with a number of public fields (like a rust/c++ struct).
The "data" must include just a single field called "fields" which is a list of
objects describing the fields of the struct. Each object must be given a "name",
"data_type", and a "default" value description. The "default" description must
be either "Required", "Optional" or "Default". If it is "Required" then the user
must supply the field value when importing a settings file. If it is "Optional"
then the internal type of the field in c++ is std::optional<"data_type"> and is
set to std::nullopt if the field is not given by the user. If it is Default then
it must be followed by a value which is given to the field if the user does not
supply a value.

Array: A list of objects of the same type (like a rust/c++ vector). The "data"
must include just a single field called "data_type" which is the data type of
the elements of the array.

Variant: Can be any of a number of different types, when parsing a value from a
user as a variant it will attempt to parse the types from the beginning of the
list of types and stops when one is successful (like a c++ variant). The "data"
must include just a single field called "data_types" which is a list of all the
type names.

Enum: Can be any of a number of predefined enum values, each enum value can
optionally wrap a single type to include extra data (like a rust enum). When a
user specifies an enum value they must specify the name of the enum value to set
along with any data for the wrapped type. Several different enum values can wrap
the same type. The "data" must include just a single field called "types" which
is a list of all the different enum values. Each element must be given a unique
"name", optionally a "description", and optionally a wrapped "data_type".

ConstrainedType: Wraps another type and enforces constraints which only allows
parsing if the constraints are respected. When parsing values through a settings
file a constrained type does not change the syntax compared to if it was no
constraints. The "data" must include two fields. "data_type" which is the data
type to be wrapped and "constraints" which is a list of boolean statements which
can include the variable "x" where the potential new value is inserted to check
if the constraint is true.

## Data Format


No matter what language to generate code for and no matter if the user supplies
a YAML or JSON file the user supplied settings file will always have the same
format. Only three types of object are used which is common to both YAML and
JSON, this is Struct/Map/Object, Array/List/Sequence and Value/String. Beneath
is a description of how to write a settings file for each termite type.

Struct: A struct is written as a Map in YAML/JSON. The keys in the Map must be
the struct.fields\[i\].name for the i'th field and the value of the key-value pair
must be defined as the type struct.fields\[i\].data_type. All fields marked as
Required must be supplied in the Map while all other fields are not required to
be present. Any key in the Map not in the struct.fields is collected in c++ into
the field "extra_fields".

Array: An array is written as a Sequence in YAML/JSON. Each element in the
Sequence must be of the type array.data_type

Variant: A variant does not have its own syntax, instead the syntax of one of
its types should be used. If multiple of the variant types use the same syntax
and has the same valid input then it will be read as the first valid type in the
types list.

Enum: An enum has two different syntax. If the enum value does not wrap any type
then it is just written as a Value where the Value is the name of the enum type.
If the enum value does wrap a type then it is written as a Map with a single
key-value pair where the key is the name of the enum type and the value of the
key-value pair is the wrapped type.

ConstrainedType: A constrained type also does not have its own syntax, instead
it inherits the syntax of its wrapped type as it will just load the wrapped type
and then check its constraints afterwards.

## Code Generation


The second part of the Termite crate is generating the code. For now it only
supports c++ with the cpp module and JSON schema with the schema module.

To generate the c++ code for the data model, use the .get_header and .get_source
methods on the model to generate the strings of the .h and the corresponding
.cpp files.

To generate the termite.hpp file use the get_termite_dependency function and
save it as "termite.hpp" on the compiler path.

To enable YAML support use the get_yaml_interface function to get the strings of
the YAML interface .h and .cpp files. These must be saved on the compiler path
as "termite-yaml.h" and "termite-yaml.cpp" respectively.

To enable JSON support use the get_json_interface function to get the strings of
the JSON interface .h and .cpp files. These must be saved on the compiler path
as "termite-json.h" and "termite-json.cpp" respectively.

To generate the schema generation run the run the .export_schema method to
receive the JSON object with the schema.

## Examples


```rust
use termite_dmg as termite;
use termite::schema;
use indoc::formatdoc;

let yaml_model = formatdoc!("
  data_types:
  - name: PositiveDouble
    data: !ConstrainedType
      data_type: number
      constraints:
      - !Arithmetic x > 0.0
  - name: Point
    description: A point in 2D space
    data: !Struct
      fields:
      - name: x
        data_type: number
        default: !Default 0.0
      - name: y
        data_type: number
        default: !Default $DEFAULT_COORDINATE$
      - name: id
        data_type: integer
        default: Optional
  - name: Size
    description: The size of a box
    data: !Struct
      fields:
      - name: w
        description: The width
        data_type: PositiveDouble
        default: Required
      - name: h
        description: The height
        data_type: PositiveDouble
        default: Required
  - name: SizeVariant
    description: Is either a Size or just a PositiveDouble if it is a square
    data: !Variant
      data_types:
      - PositiveDouble
      - Size
  - name: SizeArray
    data: !Array
      data_type: SizeVariant
  - name: Geometry
    data: !Enum
      types:
      - name: Nothing
        description: No geometry
      - name: Sizes
        description: A number of sizes
        data_type: SizeArray
      - name: Point
        description: A point
        data_type: Point
  - name: NamedGeometry
    data: !Struct
      fields:
      - name: geometry
        description: The geometry data
        data_type: Geometry
        default: !Default
          Point:
            x: 1.0
            id: 0
      - name: name
        description: The name of the geometry
        data_type: string
        default: Required
  headers:
    cpp-header: \"// My .h Header with message: $MESSAGE$\"
    cpp-source: \"// My .cpp Header and this is a dollar sign: $$\"
  footers:
    cpp-header: // My .h Footer
    cpp-source: // My .cpp Footer
  macros:
    DEFAULT_COORDINATE: 0.0
    MESSAGE: This is a macro message
  namespace:
  - my_namespace
");

let model = termite::DataModel::import_yaml(&yaml_model).unwrap();
let cpp_model = termite::cpp::DataModel::new(model.clone()).unwrap();

let termite_hpp = termite::cpp::get_termite_dependency();
let termite_yaml_hpp = termite::cpp::get_yaml_interface();
let model_h = cpp_model.get_header("HEADER_GUARD", 2);
let model_cpp = cpp_model.get_source("model", 2);
let model_schema = model.export_schema("Geometry", "my_schema");
```

YAML file for loading a my_namespace::PositiveDouble

```yaml
1.2
```

YAML file for loading a my_namespace::Point

```yaml
x: 2.0
y: -3.0
id: 5
```

Another YAML file for loading a my_namespace::Point

```yaml
y: -3.0
```

YAML file for loading a my_namespace::Size

```yaml
w: 5.2
h: 1.3
```

YAML file for loading a my_namespace::SizeVariant

```yaml
1.2
```

Another YAML file for loading a my_namespace::SizeVariant

```yaml
w: 5.2
h: 1.3
```

YAML file for loading a my_namespace::SizeArray

```yaml
- w: 5.2
  h: 1.3
- 1.2
```

YAML file for loading a my_namespace::Geometry

```yaml
Nothing
```

Another YAML file for loading a my_namespace::Geometry

```yaml
Sizes:
- w: 5.2
  h: 1.3
- 1.2
```

Another YAML file for loading a my_namespace::Geometry

```yaml
Point:
  y: -3.0
```

YAML file for loading a my_namespace::NamedGeometry

```yaml
name: A name
geometry:
  Point:
    y: -3.0
```

Another YAML file for loading a my_namespace::NamedGeometry

```yaml
name: Another name
```

## Changelog


### 0.6.0


#### Major changes


- Changed default values to use a serialization model instead of a string to
  support much more complex default values that works for more than just c++ and
  are easier to read
- Implemented macros to be used with the default values, any value surrounded by
  $ are interpreted as a macro and are replaced by the contents of that macro,
  any partial insertion can only be a string insertion and any $$ outside of a
  macro name is replaced by a single $ in the string

#### Minor changes


- Fixed minor visual bug in the c++ code generation where a double ;; would be inserted sometimes
- Fixed bug where all fields like namespace, footer and header must be included in the data model
- Added using statement to termite.hpp for boolean(bool), string(std::string),
  number(double), and integer(int64_t) to avoid having to add that to all
  headers
- Changed using statements in termite.hpp for default schema types since they
  sometimes conflicted with using definitions from other libraries

### 0.5.0


#### Major changes


- Added the schema module to generate a JSON schema for a data model

#### Minor changes


- Changed top-level doc comments to use the README file to make sure the
  documentation is up to date

### 0.4.0


#### Major changes


- Added helper functions for yaml and json to export to and import from json and
  yaml strings and files.
- Added helper functions to directly import to or export from termite generated
  types from/to json or yaml nodes, strings or files.

#### Minor changes


- Fixed bug in yaml and json when attempting to export an empty termite list or
  map to a json or yaml node. It would export them as null/empty node not as an
  empty list/map.
- Added method to termite::Result called .unwrap which throws an exception if
  the result is Err, should only be used when you know the result must be Ok.
- Updated the README file to be much clearer.

### 0.3.0


#### Major changes


- Added get_json_interface function to add json support for importing data model
  data. It works just like the get_yaml_interface function.

#### Minor changes


### 0.2.1


#### Major changes


#### Minor changes


- Split termite-yaml.hpp into a .h and a .cpp file to avoid compilation errors
  when using multiple compilation units.

### 0.2.0


#### Major changes


- Split the hpp file into a .h and .cpp file to fix linker issues when including
  in several compilation blocks.
- Removed default values from constructor for Structs and instead added static
  methods for constructors of all the fields with default values.
- Added a from_value static template method for termite::Node to convert any
  data model back into a node.

#### Minor changes


- Slightly changed the code style of the cpp code.
- Fixed bug where default value for a field in a Struct of a type defined in
  this data model could not comile if namespaces were used.

### 0.1.1


#### Minor changes


- Fixed bug where the namespace was not added to data types in the parsing code
  when those data types were custom types stopping the c++ code from compiling.
- Fixed bug where if a struct field was called x then it could not compile.
- Fixed bug where ConstrainedType fields in structs with default values could
  not compile.