File: yaml.md

package info (click to toggle)
glaze 7.0.2-3
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 9,036 kB
  • sloc: cpp: 142,035; sh: 98; ansic: 26; makefile: 12
file content (341 lines) | stat: -rw-r--r-- 8,043 bytes parent folder | download | duplicates (3)
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
# YAML

Glaze provides a YAML 1.2 reader and writer. The same compile-time reflection metadata used for JSON works for YAML, so you can reuse your `glz::meta` specializations without additional boilerplate.

> **Note:** YAML support requires a separate include. It is not included in `glaze/glaze.hpp`.

## Getting Started

Include `glaze/yaml.hpp` to access the YAML API:

```cpp
#include "glaze/yaml.hpp"

struct retry_policy
{
   int attempts = 5;
   int backoff_ms = 250;
};

template <>
struct glz::meta<retry_policy>
{
   using T = retry_policy;
   static constexpr auto value = object(&T::attempts, &T::backoff_ms);
};

struct app_config
{
   std::string host = "127.0.0.1";
   int port = 8080;
   retry_policy retry{};
   std::vector<std::string> features{"metrics"};
};

template <>
struct glz::meta<app_config>
{
   using T = app_config;
   static constexpr auto value = object(&T::host, &T::port, &T::retry, &T::features);
};

app_config cfg{};
std::string yaml{};
auto write_error = glz::write_yaml(cfg, yaml);
if (write_error) {
   const auto message = glz::format_error(write_error, yaml);
   // handle the error message
}

app_config loaded{};
auto read_error = glz::read_yaml(loaded, yaml);
if (read_error) {
   const auto message = glz::format_error(read_error, yaml);
   // handle the error message
}
```

`glz::write_yaml` and `glz::read_yaml` return an `error_ctx`. The object becomes truthy when an error occurred; pass it to `glz::format_error` to obtain a human-readable explanation.

## YAML Output Example

The `app_config` structure above produces:

```yaml
host: "127.0.0.1"
port: 8080
retry:
  attempts: 5
  backoff_ms: 250
features:
  - metrics
```

## YAML Input Example

Glaze supports both block style (with indentation) and flow style (compact) for reading:

**Block style:**
```yaml
host: localhost
port: 9000
retry:
  attempts: 6
  backoff_ms: 500
features:
  - metrics
  - debug
```

**Flow style:**
```yaml
host: localhost
port: 9000
retry: {attempts: 6, backoff_ms: 500}
features: [metrics, debug]
```

## Scalar Types

Glaze YAML supports the following scalar representations:

### Strings

```yaml
# Plain scalars (unquoted)
name: hello world

# Double-quoted with escape sequences
message: "Hello\nWorld"

# Single-quoted (literal, only '' escapes to ')
path: 'C:\Users\name'

# Literal block scalar (preserves newlines)
description: |
  This is line 1.
  This is line 2.
  This is line 3.

# Folded block scalar (folds newlines to spaces)
summary: >
  This is a long
  paragraph that will
  be folded into one line.
```

**Block scalar modifiers:**
- `|` (literal): Preserves all newlines exactly
- `>` (folded): Converts newlines to spaces (paragraph style)
- Chomping: `-` strips trailing newlines, `+` keeps all, default clips to one
- Indentation indicator: `|2` or `>4` for explicit indent level

Double-quoted strings support YAML escape sequences including:
- `\\`, `\"`, `\/`, `\n`, `\r`, `\t`, `\b`, `\f`
- `\0` (null), `\a` (bell), `\v` (vertical tab), `\e` (escape)
- `\xXX` (hex byte), `\uXXXX` (Unicode), `\UXXXXXXXX` (Unicode)
- `\N` (next line U+0085), `\_` (non-breaking space U+00A0)
- `\L` (line separator U+2028), `\P` (paragraph separator U+2029)

### Numbers

```yaml
integer: 42
negative: -17
float: 3.14
scientific: 6.022e23
hex: 0x1A
octal: 0o755
binary: 0b1010
infinity: .inf
neg_infinity: -.inf
not_a_number: .nan
```

### Booleans

```yaml
enabled: true
disabled: false
```

YAML 1.2 Core Schema is used, so `true`/`false` (case-insensitive) are recognized as booleans.

### Null

```yaml
value: null
also_null: ~
```

## Collections

### Sequences (Arrays)

**Block style:**
```yaml
items:
  - first
  - second
  - third
```

**Flow style:**
```yaml
items: [first, second, third]
```

### Mappings (Objects)

**Block style:**
```yaml
person:
  name: John
  age: 30
```

**Flow style:**
```yaml
person: {name: John, age: 30}
```

## Document Markers

Glaze supports YAML document markers:

```yaml
---
# Document start marker (optional)
key: value
...
# Document end marker (optional)
```

The `---` marker indicates the start of a document and is skipped during parsing. The `...` marker indicates the end of a document; any content after it is ignored.

## File Helpers

Glaze provides file-oriented helpers:

```cpp
std::string buffer{};
glz::write_file_yaml(cfg, "config.yaml"); // writes to disk

app_config loaded{};
glz::read_file_yaml(loaded, "config.yaml");
```

## Using the Generic API

You can use the generic `glz::read`/`glz::write` with YAML by setting the format option:

```cpp
app_config cfg{};
auto ec = glz::read<glz::opts{.format = glz::YAML}>(cfg, yaml_text);
if (ec) {
   const auto message = glz::format_error(ec, yaml_text);
   // handle error
}
```

```cpp
std::string yaml{};
auto ec = glz::write<glz::opts{.format = glz::YAML}>(cfg, yaml);
```

## YAML Options

The `glz::yaml::yaml_opts` struct provides YAML-specific options:

| Option | Default | Description |
|--------|---------|-------------|
| `error_on_unknown_keys` | `true` | Error on unknown YAML keys |
| `skip_null_members` | `true` | Skip null values when writing |
| `indent_width` | `2` | Spaces per indent level |
| `flow_style` | `false` | Use flow style (compact) output |

Example with flow style output:

```cpp
auto ec = glz::write<glz::yaml::yaml_opts{.flow_style = true}>(cfg, yaml);
// Output: {host: "127.0.0.1", port: 8080, retry: {attempts: 5, backoff_ms: 250}, features: [metrics]}
```

## Supported Types

YAML support leverages the same type system as JSON. All types that work with `glz::read_json`/`glz::write_json` also work with YAML:

- Arithmetic types (integers, floating-point)
- `std::string`, `std::string_view`
- `std::vector`, `std::array`, `std::deque`, `std::list`
- `std::map`, `std::unordered_map`
- `std::optional`, `std::unique_ptr`, `std::shared_ptr`
- `std::variant`
- `std::tuple`
- User-defined types with `glz::meta` or pure reflection
- Enums (as integers or strings with `glz::meta`)

## Tag Validation

Glaze supports YAML Core Schema tags and validates them against the C++ types being parsed. This catches type mismatches at parse time.

### Supported Tags

| Tag | Verbatim Form | Valid C++ Types |
|-----|---------------|-----------------|
| `!!str` | `!<tag:yaml.org,2002:str>` | `std::string`, `std::string_view` |
| `!!int` | `!<tag:yaml.org,2002:int>` | `int`, `int64_t`, `uint32_t`, etc. |
| `!!float` | `!<tag:yaml.org,2002:float>` | `float`, `double` |
| `!!bool` | `!<tag:yaml.org,2002:bool>` | `bool` |
| `!!null` | `!<tag:yaml.org,2002:null>` | `std::optional`, `std::unique_ptr`, pointers |
| `!!seq` | `!<tag:yaml.org,2002:seq>` | `std::vector`, `std::array`, etc. |
| `!!map` | `!<tag:yaml.org,2002:map>` | `std::map`, structs, objects |

### Examples

```yaml
# Valid: tag matches C++ type
name: !!str "Alice"
count: !!int 42
rate: !!float 3.14
enabled: !!bool true
items: !!seq [1, 2, 3]
config: !!map {key: value}
```

```cpp
// When parsing into int, !!str tag causes an error
std::string yaml = "!!str 42";
int value{};
auto ec = glz::read_yaml(value, yaml);
// ec.ec == glz::error_code::syntax_error (tag mismatch!)
```

### Tag Compatibility

- `!!int` is valid for floating-point types (widening conversion allowed)
- `!!float` is NOT valid for integer types
- Unknown or custom tags (e.g., `!mytag`, `!!custom`) produce `feature_not_supported` error

## Limitations

The current YAML implementation has some limitations compared to the full YAML 1.2 specification:

### Not Supported

- **Anchors and aliases** (`&anchor`, `*alias`) - These will produce a `feature_not_supported` error
- **Custom tags** (`!mytag`) - Only YAML Core Schema tags are supported
- **Multi-document streams** - Only single documents are supported
- **Complex keys** - Only simple scalar keys are supported

### Tab Indentation

YAML forbids tab characters for indentation. Using tabs will produce a `syntax_error`:

```yaml
# This will error:
key:
	value  # Tab character - not allowed!
```

Always use spaces for indentation in YAML.