libyml 0.0.6

DEPRECATED — `libyml` is unmaintained. This release is a thin compatibility shim that forwards every call to `unsafe-libyaml` (the upstream C-libyaml translation `libyml` was originally forked from). Please migrate to `unsafe-libyaml`, `yaml-rust2`, or `noyalib`.
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
413
414
# Migrating off `libyml`

`libyml` is unmaintained. The `0.0.6` release is a thin
compatibility shim so existing call sites keep working while you
migrate to a maintained alternative.

> ## ⚠️ Security: RUSTSEC-2025-0067 is structurally fixed in 0.0.6
>
> [RUSTSEC-2025-0067]https://rustsec.org/advisories/RUSTSEC-2025-0067.html
> flagged all `libyml ≤ 0.0.5` as unsound — the
> `libyml::string::yaml_string_extend` function had a code path
> that could trigger undefined behaviour. **Upgrading to
> `libyml = "0.0.6"` removes the vulnerable surface entirely**> the entire `libyml::string` module is gone from the source tree
> alongside the rest of the hand-translated C-libyaml copy, and
> every public function is now re-exported from the upstream
> `unsafe-libyaml` crate.
>
> **`cargo audit` will still warn anyway.** The RustSec advisory
> database tracks the crate's unmaintained status across all
> versions and has chosen not to mark `0.0.6` as patched. The
> warning is a maintainer-status signal at this point, not a
> code-presence signal. To suppress it in your own project, copy
> the snippet from the
> [README's "cargo audit" section]./README.md#cargo-audit-will-still-warn--heres-why-and-how-to-handle-it,
> or migrate fully to one of the maintained alternatives below.

The shim itself depends on
[`unsafe-libyaml`](https://crates.io/crates/unsafe-libyaml) — the
upstream Rust translation of C `libyaml` that `libyml` was
originally forked from — for its implementation. That's an
implementation detail, not a recommendation that you must migrate
to `unsafe-libyaml` specifically. Three crates are realistic
destinations; pick the one that fits.

| Destination | Migration shape | When it's the right choice |
| :--- | :--- | :--- |
| **[`unsafe-libyaml`]https://crates.io/crates/unsafe-libyaml** | Drop-in upstream — rename PascalCase types/consts to snake_case / SCREAMING_SNAKE_CASE | Codebases that want to stay on the raw libyaml-shaped FFI API on a maintained backend |
| **[`yaml-rust2`]https://crates.io/crates/yaml-rust2** | Not FFI-shaped — `YamlLoader::load_from_str` returns a `Yaml` AST | Users who want to drop the C-libyaml model entirely while keeping a low-level parser primitive in pure Rust |
| **[`noyalib`]https://crates.io/crates/noyalib** | Higher-level typed API (`from_str::<T>` / `Value`); pure-Rust, `#![forbid(unsafe_code)]` | Users who can move from event-stream parsing to typed deserialisation — usually the cleanest end-state |

The rest of this document describes each migration path, the
public-surface mapping, the modules that are gone in this shim,
and the behavioural deltas to know about.

---

## Path A — Stay on `libyml = "0.0.6"` (stop-gap)

If you cannot migrate right now, depending on the shim keeps your
code compiling. The compiler emits a deprecation warning at every
`use libyml::*` import so you can budget the work.

```toml
[dependencies]
libyml = "0.0.6"
```

No code changes required, with three caveats covered in the
[Behavioural notes](#behavioural-notes) below. Roughly:

- C-int boolean arguments (`1` / `0`) flip to Rust `bool`
  (`true` / `false`) — hard compile error at the call site, easy
  to fix.
- `libyml::success::Success` is no longer a nameable type — read
  `.ok` on the return value directly; the shim's helpers
  (`is_success` / `is_failure`) now take `bool`.
- Enum variants kept their PascalCase names in **value position**
  but rename to SCREAMING_SNAKE_CASE in `match` arms.

---

## Path B — Migrate to `unsafe-libyaml`

```diff
-[dependencies]
-libyml = "0.0"
+[dependencies]
+unsafe-libyaml = "0.2"
```

```diff
-use libyml::{yaml_parser_initialize, YamlParserT, YamlUtf8Encoding};
+use unsafe_libyaml::{
+    yaml_parser_initialize,
+    yaml_parser_t as YamlParserT,
+    YAML_UTF8_ENCODING,
+};
```

Or rename at the import site for a one-line diff:

```rust
use unsafe_libyaml as libyml;
// then update the PascalCase type/const names individually.
```

That is the entire migration for codebases that were using
`libyml` as a literal libyaml-shaped FFI surface. The
public-surface mapping is in [§ Public-surface
mapping](#public-surface-mapping) below.

---

## Path C — Migrate to `yaml-rust2` (pure-Rust low-level)

```diff
-[dependencies]
-libyml = "0.0"
+[dependencies]
+yaml-rust2 = "0.9"
```

```diff
-let mut parser = MaybeUninit::<YamlParserT>::uninit();
-yaml_parser_initialize(parser.as_mut_ptr());
-let mut parser = parser.assume_init();
-yaml_parser_set_input_string(&mut parser, src.as_ptr(), src.len() as u64);
-loop {
-    let mut event = MaybeUninit::<YamlEventT>::uninit();
-    yaml_parser_parse(&mut parser, event.as_mut_ptr());
-    // ... handle event ...
-}
+use yaml_rust2::YamlLoader;
+let docs = YamlLoader::load_from_str(src)?;
+let v = &docs[0];
+// ... walk the Yaml AST ...
```

`yaml-rust2` is a pure-Rust YAML parser — the active continuation
of the original `yaml-rust` crate. It returns a `Yaml` enum (its
own AST), **not a stream of events**. Migrating means restructuring
event-loop code into AST traversal. This is the right choice when
you actually want pure-Rust parser primitives — custom loaders,
lint tools, format-preserving editors — and can drop the C-libyaml
model.

For typed `from_str::<T>` flows, prefer `noyalib`.

---

## Path D — Migrate to `noyalib` (modern typed API)

```diff
-[dependencies]
-libyml = "0.0"
+[dependencies]
+noyalib = "0.0.5"
```

```diff
-// Manual event-stream walk to extract `name` and `port`
-let mut parser = MaybeUninit::<YamlParserT>::uninit();
-yaml_parser_initialize(parser.as_mut_ptr());
-// ... ~30 lines of event dispatch ...
+use noyalib::from_str;
+#[derive(serde::Deserialize)]
+struct Config { name: String, port: u16 }
+let cfg: Config = from_str(yaml_str)?;
```

`noyalib` is a modern, pure-Rust, `#![forbid(unsafe_code)]` YAML
library with a high-level typed API (`from_str::<T>` / `Value`),
configurable parser limits, and YAML 1.2 strict resolution. It
covers the use case where `libyml` was a building block for a
config loader or document model — i.e. exactly the cases where
the event-stream API was incidental rather than essential.

| Surface | `noyalib` mapping |
| :--- | :--- |
| Hand-written event-stream walk for typed extraction | `noyalib::from_str::<T>` |
| `yaml_parser_load` → document tree | `noyalib::from_str::<noyalib::Value>` |
| `yaml_emitter_emit` event-stream emission | `noyalib::to_string(&value)` |
| Anchor / alias resolution (manual `&a` / `*a` walking) | Transparent — `noyalib` resolves anchors during parse |
| Custom tag handling | `Value::Tagged` variant preserved exactly |
| Streaming over large input | `noyalib::Deserializer::from_reader(...)` |

---

## Public-surface mapping

The common surface is preserved name-for-name through the
`libyml 0.0.6` shim, and maps directly to `unsafe-libyaml` for
users taking Path B:

| `libyml` (≤ 0.0.5)                          | `libyml` 0.0.6 shim                       | Direct `unsafe-libyaml` equivalent           |
| ------------------------------------------- | ----------------------------------------- | -------------------------------------------- |
| `libyml::yaml_parser_initialize`            | unchanged                                 | `unsafe_libyaml::yaml_parser_initialize`     |
| `libyml::yaml_parser_delete`                | unchanged                                 | `unsafe_libyaml::yaml_parser_delete`         |
| `libyml::yaml_parser_set_input_string`      | unchanged                                 | `unsafe_libyaml::yaml_parser_set_input_string` |
| `libyml::yaml_parser_set_input`             | unchanged                                 | `unsafe_libyaml::yaml_parser_set_input`      |
| `libyml::yaml_parser_set_encoding`          | unchanged                                 | `unsafe_libyaml::yaml_parser_set_encoding`   |
| `libyml::yaml_parser_parse`                 | unchanged                                 | `unsafe_libyaml::yaml_parser_parse`          |
| `libyml::yaml_parser_scan`                  | unchanged                                 | `unsafe_libyaml::yaml_parser_scan`           |
| `libyml::yaml_parser_load`                  | unchanged                                 | `unsafe_libyaml::yaml_parser_load`           |
| `libyml::yaml_emitter_initialize`           | unchanged                                 | `unsafe_libyaml::yaml_emitter_initialize`    |
| `libyml::yaml_emitter_delete`               | unchanged                                 | `unsafe_libyaml::yaml_emitter_delete`        |
| `libyml::yaml_emitter_set_output`           | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_output`    |
| `libyml::yaml_emitter_set_output_string`    | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_output_string` |
| `libyml::yaml_emitter_set_encoding`         | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_encoding`  |
| `libyml::yaml_emitter_set_canonical`        | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_canonical` |
| `libyml::yaml_emitter_set_indent`           | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_indent`    |
| `libyml::yaml_emitter_set_width`            | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_width`     |
| `libyml::yaml_emitter_set_unicode`          | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_unicode`   |
| `libyml::yaml_emitter_set_break`            | unchanged                                 | `unsafe_libyaml::yaml_emitter_set_break`     |
| `libyml::yaml_emitter_open`                 | unchanged                                 | `unsafe_libyaml::yaml_emitter_open`          |
| `libyml::yaml_emitter_close`                | unchanged                                 | `unsafe_libyaml::yaml_emitter_close`         |
| `libyml::yaml_emitter_dump`                 | unchanged                                 | `unsafe_libyaml::yaml_emitter_dump`          |
| `libyml::yaml_emitter_emit`                 | unchanged                                 | `unsafe_libyaml::yaml_emitter_emit`          |
| `libyml::yaml_emitter_flush`                | unchanged                                 | `unsafe_libyaml::yaml_emitter_flush`         |
| `libyml::yaml_event_delete`                 | unchanged                                 | `unsafe_libyaml::yaml_event_delete`          |
| `libyml::yaml_token_delete`                 | unchanged                                 | `unsafe_libyaml::yaml_token_delete`          |
| `libyml::yaml_*_event_initialize`           | unchanged                                 | `unsafe_libyaml::yaml_*_event_initialize`    |
| `libyml::yaml_document_initialize`          | unchanged                                 | `unsafe_libyaml::yaml_document_initialize`   |
| `libyml::yaml_document_delete`              | unchanged                                 | `unsafe_libyaml::yaml_document_delete`       |
| `libyml::yaml_document_get_root_node`       | unchanged                                 | `unsafe_libyaml::yaml_document_get_root_node`|
| `libyml::yaml_document_get_node`            | unchanged                                 | `unsafe_libyaml::yaml_document_get_node`     |
| `libyml::YamlParserT`                       | unchanged (alias)                         | `unsafe_libyaml::yaml_parser_t`              |
| `libyml::YamlEmitterT`                      | unchanged (alias)                         | `unsafe_libyaml::yaml_emitter_t`             |
| `libyml::YamlEventT`                        | unchanged (alias)                         | `unsafe_libyaml::yaml_event_t`               |
| `libyml::YamlTokenT`                        | unchanged (alias)                         | `unsafe_libyaml::yaml_token_t`               |
| `libyml::YamlDocumentT`                     | unchanged (alias)                         | `unsafe_libyaml::yaml_document_t`            |
| `libyml::YamlNodeT`                         | unchanged (alias)                         | `unsafe_libyaml::yaml_node_t`                |
| `libyml::YamlMarkT`                         | unchanged (alias)                         | `unsafe_libyaml::yaml_mark_t`                |
| `libyml::YamlVersionDirectiveT`             | unchanged (alias)                         | `unsafe_libyaml::yaml_version_directive_t`   |
| `libyml::YamlTagDirectiveT`                 | unchanged (alias)                         | `unsafe_libyaml::yaml_tag_directive_t`       |
| `libyml::YamlUtf8Encoding` (value position) | unchanged (`pub const`)                   | `unsafe_libyaml::YAML_UTF8_ENCODING`         |
| `libyml::YamlPlainScalarStyle` (value)      | unchanged (`pub const`)                   | `unsafe_libyaml::YAML_PLAIN_SCALAR_STYLE`    |
| `libyml::YamlBlockMappingStyle` (value)     | unchanged (`pub const`)                   | `unsafe_libyaml::YAML_BLOCK_MAPPING_STYLE`   |
| All other event / style / encoding / error / node variants | unchanged (`pub const`) in value position; rename to SCREAMING_SNAKE_CASE in patterns | `unsafe_libyaml::YAML_*`                      |

For `yaml-rust2` and `noyalib`, see Path C and Path D above —
those crates do not aim for libyaml surface compatibility.

---

## Retained in 0.0.6 — path-form sub-modules

Most of the previous public sub-module surface is preserved
**name-for-name** through the shim. The modules below are thin
re-exports pointing at the upstream `unsafe-libyaml` items, so
historical `use libyml::api::yaml_parser_set_input_string` etc.
imports keep resolving with zero source changes (the three
behavioural deltas below still apply at the call sites).

| Path                  | Status in 0.0.6                                                 |
| --------------------- | --------------------------------------------------------------- |
| `libyml::api::*`      | Re-exports parser/emitter init + event initialisers             |
| `libyml::decode::*`   | Re-exports `yaml_parser_initialize` / `_delete`                 |
| `libyml::document::*` | Re-exports `yaml_document_*` helpers                            |
| `libyml::dumper::*`   | Re-exports `yaml_emitter_open` / `_close` / `_dump`             |
| `libyml::loader::*`   | Re-exports `yaml_parser_load`                                   |
| `libyml::yaml::*`     | Re-exports every PascalCase type alias and PascalCase variant constant; `yaml_char_t` retained as `pub type … = u8` |
| `libyml::success::*`  | Retains `is_success(bool)` and `is_failure(bool)` helpers       |

## Removed in 0.0.6

The implementation-detail modules — and the handful of internal
helpers that previous releases exposed inside the otherwise
retained sub-modules — are **gone** in the shim. If your code
depended on any of these, the right replacement depends on which
destination you chose:

| Removed from `libyml`                                       | What it was                                          | Where it goes                                                                       |
| ----------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `libyml::memory::*` *(stub module retained)*                | `yaml_malloc` / `yaml_free` / `yaml_realloc` / `yaml_strdup` | None — the upstream uses Rust's `alloc` directly. Use `std::alloc::{alloc, dealloc}` or `Vec`/`Box`. The module remains as an empty stub so `use libyml::memory;` keeps compiling |
| `libyml::string::*` *(stub module retained)*                | `yaml_string_extend` / `_join` — the unsound helper [RUSTSEC-2025-0067]https://rustsec.org/advisories/RUSTSEC-2025-0067.html flags | None — build strings with Rust's `Vec` / `String`. Stub module retained for the same source-compatibility reason as `memory` |
| `libyml::internal::*`                                       | Hand-translated parser/emitter state-machine helpers | None — `unsafe-libyaml` keeps its equivalents private                                |
| `libyml::macros::*`                                         | Internal `__assert!` / `do_loop!` macros             | None — implementation details of the C copy                                         |
| `libyml::ops::*`                                            | `ForceAdd` / `ForceInto` / `die` helpers             | None — the upstream uses its own internal equivalents                               |
| `libyml::utils::*`                                          | Internal `memory_macros` module                      | None — implementation details of the C copy                                         |
| `libyml::externs::*`                                        | C-style `malloc` / `free` / `memcpy` / `memmove` re-exports | None — the upstream uses Rust's `alloc` directly                              |
| `libyml::libc`                                              | Re-exports of `core::ffi::c_*` primitives            | Use `core::ffi::*` directly                                                         |
| `libyml::loader::yaml_parser_set_composer_error`            | Internal composer-error injection helper             | Inspect `parser.problem` after `yaml_parser_parse` / `yaml_parser_load` failure     |
| `libyml::dumper::yaml_emitter_dump_node` / `_scalar` / `_sequence` / `_mapping` | Internal sub-routines of `yaml_emitter_dump`         | None — drive emission through the public `yaml_emitter_dump`                        |
| `libyml::success::Success` (nameable)                       | `#[derive(PartialEq, Debug)]` struct wrapping `bool` | Read `.ok` on the upstream return value directly; the shim keeps `is_success(bool)` / `is_failure(bool)` |
| `libyml::yaml::*` derive helpers (`Default`, `default()`)   | `Default` impls on `yaml_mark_t`, `yaml_version_directive_t`, `yaml_encoding_t`, `yaml_break_t`, `yaml_scalar_style_t`, `yaml_error_type_t`, … | None — `unsafe-libyaml` does not derive `Default` on these types. Construct values explicitly |
| `libyml::yaml::Yaml*` variants in `match` patterns          | PascalCase enum-variant patterns                     | Switch to the upstream's `YAML_*` SCREAMING_SNAKE_CASE names in pattern position; value-position usage is unchanged |
| `src/bin/run-emitter-test-suite.rs`                         | yaml-test-suite emitter runner                       | Upstream `unsafe-libyaml`'s own test suite covers the equivalent                    |
| `src/bin/run-parser-test-suite.rs`                          | yaml-test-suite parser runner                        | Upstream `unsafe-libyaml`'s own test suite covers the equivalent                    |
| `src/bin/cstr/*`                                            | Internal CStr helper for the test-suite binaries     | None — implementation detail of the removed runners                                 |

This repository is archived — direct migration questions to the
destination crate's issue tracker.

---

## Behavioural notes

The shim is backed by `unsafe-libyaml`, whose upstream code has
diverged from the fork's snapshot in three user-visible ways:

1. **Boolean parameters take `bool`, not `c_int`.** Previously
   `yaml_scalar_event_initialize(..., 1, 1, style)` compiled with
   `c_int` arguments — `1` and `0` were valid values. Under the
   shim the function signature comes from `unsafe-libyaml`, so
   the same call site needs `true` / `false` instead. This is a
   hard compile error, not a silent change: the compiler points
   at every offending argument.

   ```diff
   -yaml_scalar_event_initialize(ev, anchor, tag, val, len, 1, 1, style);
   +yaml_scalar_event_initialize(ev, anchor, tag, val, len, true, true, style);
   ```

2. **`Success` is no longer a nameable type.** The upstream keeps
   its `Success` struct in a private module. The value still
   flows out of every `yaml_*` call and `.ok: bool` is still
   public, so reading the success flag works exactly as before —
   but you can no longer write a function signature mentioning
   the type:

   ```diff
   -fn check(r: libyml::success::Success) -> bool { is_success(r) }
   +fn check(ok: bool) -> bool { is_success(ok) }
   ```

   The retained `libyml::success::{is_success, is_failure}`
   helpers now take `bool` directly. Chain them as
   `is_success(call(...).ok)`.

3. **Enum variants rename PascalCase → SCREAMING_SNAKE_CASE in
   `match` arms.** The shim defines `pub const YamlUtf8Encoding`
   (etc.) so the historical names still work in **value
   position**:

   ```rust
   yaml_emitter_set_encoding(&mut emitter, YamlUtf8Encoding); // ok
   ```

   In refutable **patterns**, the upstream's SCREAMING_SNAKE_CASE
   name is required:

   ```diff
   - match enc { YamlUtf8Encoding => /* … */, _ => /* … */ }
   + match enc { unsafe_libyaml::YAML_UTF8_ENCODING => /* … */, _ => /* … */ }
   ```

   Both spellings are re-exported from `libyml`, so the imports
   side stays clean. The constraint is purely about how Rust
   resolves pattern arms vs. expressions.

Migrations to `yaml-rust2` or `noyalib` sidestep all three of
these because their public APIs don't share shapes with C
`libyaml` to begin with.

---

## MSRV

`libyml 0.0.6` requires **Rust 1.56.0** — the same floor as
`unsafe-libyaml`. The previous releases also required 1.56, so
this is not a bump.

---

## Test and example coverage in 0.0.6

The 0.0.6 shim is wire-compatible with typical user code (parser
/ emitter init + parse / emit cycles work transparently). The
original `libyml ≤ 0.0.5` test and example files are kept in this
repo where they could be brought across with a small mechanical
patch — they serve as a *worked-example* of what the migration
looks like from the downstream side. Where the original tests
probed the previous implementation's **private fields**, **derived
`Default` impls**, or **deleted internal modules**
(`internal`, `macros`, `externs`, the `string::yaml_string_extend`
unsound helper), they were removed because they reflect
implementation-detail coverage rather than downstream user code.

### Tests retained (3 files, 18 tests, all pass)

| File | Source | Changes applied | Tests |
| :--- | :--- | :--- | ---: |
| `tests/test_decode.rs` | from 0.0.5 | **verbatim**`libyml::decode::*` path module re-exports through the shim | 8 |
| `tests/test_lib.rs` | from 0.0.5 | two-line patch (`is_success(call)``is_success(call.ok)`, drop `#![no_std]`) | 5 |
| `tests/shim.rs` | new | smoke suite covering parser init, parse-first-event, emit-mapping round-trip, type aliases, `success` helpers | 5 |

### Examples retained (3 runnable, all execute to completion)

| Path | Source | Changes applied |
| :--- | :--- | :--- |
| `examples/example.rs` | from 0.0.5 (aggregator shape) | runs `examples/apis/main.rs` then a parse + emit demo |
| `examples/apis/main.rs` | from 0.0.5 | parser slabs kept; `memory` + `string` slabs kept as commented-out blocks with Rust-native replacements inline |
| `examples/migration.rs` | new | single-file shim demo (parse a 2-line doc and count events) |

### Tests removed (probed the old implementation's private shape)

| File | Why |
| :--- | :--- |
| `tests/test_api.rs` | Used `libyml::memory::yaml_malloc` / `_strdup` and `libyml::externs::free` — the C-libyaml allocator surface is removed in 0.0.6 (the upstream uses Rust's `alloc` directly) |
| `tests/test_document.rs` | Called `YamlDocumentT::cleanup()` and constructed `yaml_mark_t::default()` — internal helpers not exposed by `unsafe-libyaml` |
| `tests/test_dumper.rs` | Read private fields (`emitter.opened`, `emitter.closed`, `emitter.write_handler`) — public in the fork's reimplementation, private in `unsafe-libyaml` |
| `tests/test_emitter.rs` | Imported the deleted `src/bin/run-emitter-test-suite.rs` runner |
| `tests/test_internal.rs` | Tested the removed `libyml::internal` module |
| `tests/test_loader.rs` | Imported `libyml::loader::yaml_parser_set_composer_error` — internal helper not in the upstream's public API |
| `tests/test_macros.rs` | Imported the removed `libyml::macros`, `libyml::libc`, `libyml::externs` and the `yaml_string_extend` unsound helper (RUSTSEC-2025-0067) |
| `tests/test_memory.rs` | Imported the removed `libyml::memory` allocator wrappers |
| `tests/test_parser.rs`, `test_parser_error.rs` | Imported the deleted `src/bin/run-parser-test-suite.rs` runner |
| `tests/test_string.rs` | Imported the removed `libyml::string` module (the unsound `yaml_string_extend` helper RUSTSEC-2025-0067 covers) |
| `tests/test_yaml.rs` | Called `YamlEncodingT::default()` and used `YamlAnyEncoding` / `YamlAnyScalarStyle` / etc. as enum-variant `match` patterns — both rely on derive impls and the variant-position rename gap |
| `tests/data/*` (libyml-test-suite proc macros) | yaml-test-suite harness; upstream `unsafe-libyaml` runs its own equivalent suite |

### Examples removed

| Path | Why |
| :--- | :--- |
| `src/bin/run-emitter-test-suite.rs` | Test-suite runner depending on removed internals |
| `src/bin/run-parser-test-suite.rs` | Test-suite runner depending on removed internals |
| `src/bin/cstr/*` | Internal CStr helper for the removed test-suite binaries |

If you depended on any of these, pick the destination crate from
the table at the top of this document — its public surface
offers the equivalent functionality.