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.
|