Skip to main content

twig_sys/
lib.rs

1//! Low-level FFI bindings for Twig's C ABI, plus the build script that links
2//! the native `libtwig.a`.
3//!
4//! This crate is the `-sys` layer: it exposes the raw `extern "C"` functions,
5//! the `#[repr(C)]` type mirrors, and the status/format constants, and nothing
6//! else. The safe, ergonomic API lives in the `twig-doc` crate, which depends
7//! on this one. Direct use is `unsafe` and unstable across ABI-version bumps —
8//! see [`TWIG_ABI_VERSION`].
9#![allow(non_camel_case_types)]
10
11use std::os::raw::{c_char, c_int};
12
13/// The C ABI contract version this binding is written against; see
14/// `twig_abi_version`. Must match the value baked into the linked library
15/// (asserted at runtime by the `abi_version_matches` test in `lib.rs`).
16pub const TWIG_ABI_VERSION: u32 = 4;
17
18// Freeze the canonical 64-bit layout of every `#[repr(C)]` mirror below so it
19// can never silently drift from the Zig `extern struct` it shadows. These are
20// the same offsets asserted on the Zig side in `src/c_abi.zig`; a change on
21// either side that isn't matched on the other fails to compile. Gated on 64-bit
22// (the offsets are the LP64/LLP64 layout); 32-bit targets pack tighter but the
23// C ABI still keeps both languages in agreement.
24#[cfg(target_pointer_width = "64")]
25const _: () = {
26    use std::mem::offset_of;
27    use std::mem::size_of;
28
29    assert!(size_of::<TwigSpan>() == 16);
30    assert!(offset_of!(TwigSpan, start) == 0);
31    assert!(offset_of!(TwigSpan, end) == 8);
32
33    assert!(size_of::<TwigQueryMatch>() == 56);
34    assert!(offset_of!(TwigQueryMatch, node_id) == 0);
35    assert!(offset_of!(TwigQueryMatch, span) == 8);
36    assert!(offset_of!(TwigQueryMatch, content_span) == 24);
37    assert!(offset_of!(TwigQueryMatch, has_content_span) == 40);
38    assert!(offset_of!(TwigQueryMatch, kind) == 48);
39
40    assert!(size_of::<TwigChange>() == 32);
41    assert!(offset_of!(TwigChange, old_span) == 0);
42    assert!(offset_of!(TwigChange, new_span) == 16);
43
44    assert!(size_of::<TwigFlatNode>() == 144);
45    assert!(offset_of!(TwigFlatNode, id) == 0);
46    assert!(offset_of!(TwigFlatNode, parent) == 4);
47    assert!(offset_of!(TwigFlatNode, first_child) == 8);
48    assert!(offset_of!(TwigFlatNode, next_sibling) == 12);
49    assert!(offset_of!(TwigFlatNode, span) == 16);
50    assert!(offset_of!(TwigFlatNode, content_span) == 32);
51    assert!(offset_of!(TwigFlatNode, has_content_span) == 48);
52    assert!(offset_of!(TwigFlatNode, level) == 52);
53    assert!(offset_of!(TwigFlatNode, kind) == 56);
54    assert!(offset_of!(TwigFlatNode, text_ptr) == 64);
55    assert!(offset_of!(TwigFlatNode, text_len) == 72);
56    assert!(offset_of!(TwigFlatNode, destination_ptr) == 80);
57    assert!(offset_of!(TwigFlatNode, destination_len) == 88);
58    assert!(offset_of!(TwigFlatNode, head) == 96);
59    assert!(offset_of!(TwigFlatNode, alignment) == 100);
60    assert!(offset_of!(TwigFlatNode, name_ptr) == 104);
61    assert!(offset_of!(TwigFlatNode, name_len) == 112);
62    assert!(offset_of!(TwigFlatNode, attrs_ptr) == 120);
63    assert!(offset_of!(TwigFlatNode, attrs_len) == 128);
64    assert!(offset_of!(TwigFlatNode, directive_form) == 136);
65
66    assert!(size_of::<TwigKeyVal>() == 32);
67    assert!(offset_of!(TwigKeyVal, key) == 0);
68    assert!(offset_of!(TwigKeyVal, key_len) == 8);
69    assert!(offset_of!(TwigKeyVal, value) == 16);
70    assert!(offset_of!(TwigKeyVal, value_len) == 24);
71};
72
73#[repr(transparent)]
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
75pub struct TwigStatus(pub c_int);
76
77#[allow(dead_code)]
78impl TwigStatus {
79    pub const OK: c_int = 0;
80    pub const INVALID_ARGUMENT: c_int = 1;
81    pub const PARSE_ERROR: c_int = 2;
82    pub const OUT_OF_MEMORY: c_int = 3;
83    pub const UNSUPPORTED_FORMAT: c_int = 4;
84    pub const NOT_FOUND: c_int = 5;
85    pub const AMBIGUOUS: c_int = 6;
86    pub const NOT_EDITABLE: c_int = 7;
87    pub const EDIT_CONFLICT: c_int = 8;
88    pub const UNSAFE_METADATA: c_int = 9;
89    pub const INTERNAL_ERROR: c_int = 255;
90}
91
92#[repr(C)]
93#[derive(Clone, Copy, Debug, Eq, PartialEq)]
94pub enum TwigFormat {
95    Djot = 1,
96    Markdown = 2,
97    Xml = 3,
98    Html = 4,
99}
100
101/// Markdown extension flags for the `md_flags` bitmask of `twig_parse_ext` and
102/// `twig_editor_create_ext`.
103pub const TWIG_MD_DIRECTIVES: u32 = 1 << 0;
104pub const TWIG_MD_MATH: u32 = 1 << 1;
105pub const TWIG_MD_HTML_ELEMENTS: u32 = 1 << 2;
106
107pub enum TwigDocument {}
108
109pub enum TwigEditor {}
110
111pub enum TwigBuilder {}
112
113/// C ABI mirror of Zig's `TwigKeyVal` — one `(key, value)` attribute pair. Used
114/// on the read path ([`TwigFlatNode::attrs_ptr`], borrowed) and the write path
115/// (`twig_builder_set_attrs`, copied). A NULL `value` is a bare attribute.
116#[repr(C)]
117#[derive(Clone, Copy, Debug)]
118pub struct TwigKeyVal {
119    pub key: *const u8,
120    pub key_len: usize,
121    pub value: *const u8,
122    pub value_len: usize,
123}
124
125/// C ABI mirror of Zig's `TwigSpan` — a byte range `[start, end)`.
126#[repr(C)]
127#[derive(Clone, Copy, Debug, Eq, PartialEq)]
128pub struct TwigSpan {
129    pub start: usize,
130    pub end: usize,
131}
132
133/// C ABI mirror of Zig's `TwigQueryMatch` — one node returned by
134/// `twig_document_query`. `content_span` is only meaningful when
135/// `has_content_span` is non-zero. `kind` is a NUL-terminated node-kind name
136/// in static, library-owned storage (never freed).
137#[repr(C)]
138#[derive(Clone, Copy, Debug)]
139pub struct TwigQueryMatch {
140    pub node_id: u32,
141    pub span: TwigSpan,
142    pub content_span: TwigSpan,
143    pub has_content_span: c_int,
144    pub kind: *const c_char,
145}
146
147/// The sentinel `node_id` for "no such node" in a [`TwigFlatNode`] link field.
148pub const TWIG_NO_NODE: u32 = u32::MAX;
149
150/// C ABI mirror of Zig's `TwigChange` — the byte effect of an edit. `old_span`
151/// is the replaced range in the pre-edit source; `new_span` is the range the
152/// replacement occupies in the post-edit source (same start).
153#[repr(C)]
154#[derive(Clone, Copy, Debug)]
155pub struct TwigChange {
156    pub old_span: TwigSpan,
157    pub new_span: TwigSpan,
158}
159
160/// C ABI mirror of Zig's `TwigFlatNode` — one node of the editor's flat tree
161/// snapshot. Link fields (`parent`/`first_child`/`next_sibling`) are ids or
162/// [`TWIG_NO_NODE`]. `content_span` is meaningful only when `has_content_span`.
163/// `kind` is static, library-owned storage; `text`/`destination` pointers
164/// borrow the current parse's payloads (NULL when the kind carries none).
165/// `head`/`alignment` carry a `row`/`cell` payload, each `-1` for a kind that
166/// has none (see [`TWIG_HEAD_NONE`] / [`TWIG_ALIGN_NONE`]). `name_ptr` is a
167/// generic element's tag name — or a `directive`'s type — and NULL for every
168/// other kind; `directive_form` is a [`TWIG_DIRECTIVE_NONE`]-defaulted code for
169/// which of the three surface forms a directive took; `attrs_ptr` points at
170/// `attrs_len` [`TwigKeyVal`]s (NULL/0 when the node has no attributes). Both
171/// borrow the current parse's payloads with the same lifetime as `text_ptr`.
172#[repr(C)]
173#[derive(Clone, Copy, Debug)]
174pub struct TwigFlatNode {
175    pub id: u32,
176    pub parent: u32,
177    pub first_child: u32,
178    pub next_sibling: u32,
179    pub span: TwigSpan,
180    pub content_span: TwigSpan,
181    pub has_content_span: c_int,
182    pub level: u32,
183    pub kind: *const c_char,
184    pub text_ptr: *const u8,
185    pub text_len: usize,
186    pub destination_ptr: *const u8,
187    pub destination_len: usize,
188    pub head: c_int,
189    pub alignment: c_int,
190    pub name_ptr: *const u8,
191    pub name_len: usize,
192    pub attrs_ptr: *const TwigKeyVal,
193    pub attrs_len: usize,
194    pub directive_form: c_int,
195}
196
197/// `TwigFlatNode::head` for a node that is neither a `row` nor a `cell`.
198pub const TWIG_HEAD_NONE: c_int = -1;
199
200/// `TwigFlatNode::alignment` codes; `NONE` means the node isn't a `cell`.
201/// `NONE` is part of the ABI contract even though `Alignment::from_c` folds it
202/// into its catch-all, so spell it out rather than leaving the -1 a mystery.
203#[allow(dead_code)]
204pub const TWIG_ALIGN_NONE: c_int = -1;
205pub const TWIG_ALIGN_DEFAULT: c_int = 0;
206pub const TWIG_ALIGN_LEFT: c_int = 1;
207pub const TWIG_ALIGN_RIGHT: c_int = 2;
208pub const TWIG_ALIGN_CENTER: c_int = 3;
209
210/// `TwigFlatNode::directive_form` codes — the generic-directives proposal's
211/// three spellings: `:name[x]` (text), `::name{…}` (leaf), `:::name{…}` … `:::`
212/// (container). These double as `twig_builder_add_directive`'s `form` argument.
213/// `NONE` means the node isn't a `directive` at all; like [`TWIG_ALIGN_NONE`] it
214/// is a read-path-only code, never something you can build with.
215#[allow(dead_code)]
216pub const TWIG_DIRECTIVE_NONE: c_int = -1;
217pub const TWIG_DIRECTIVE_TEXT: c_int = 0;
218pub const TWIG_DIRECTIVE_LEAF: c_int = 1;
219pub const TWIG_DIRECTIVE_CONTAINER: c_int = 2;
220
221// `op` codes for `twig_editor_table_edit` — mirror of `TwigTableOp` in twig.h.
222pub const TWIG_TABLE_INSERT_ROW: c_int = 0;
223pub const TWIG_TABLE_DELETE_ROW: c_int = 1;
224pub const TWIG_TABLE_INSERT_COLUMN: c_int = 2;
225pub const TWIG_TABLE_DELETE_COLUMN: c_int = 3;
226pub const TWIG_TABLE_SET_ALIGNMENT: c_int = 4;
227pub const TWIG_TABLE_MOVE_ROW: c_int = 5;
228pub const TWIG_TABLE_MOVE_COLUMN: c_int = 6;
229
230unsafe extern "C" {
231    pub fn twig_abi_version() -> u32;
232    pub fn twig_version() -> u32;
233    pub fn twig_version_string() -> *const c_char;
234    pub fn twig_parse(
235        input: *const u8,
236        input_len: usize,
237        format: c_int,
238        out_doc: *mut *mut TwigDocument,
239    ) -> TwigStatus;
240    pub fn twig_parse_ext(
241        input: *const u8,
242        input_len: usize,
243        format: c_int,
244        md_flags: u32,
245        out_doc: *mut *mut TwigDocument,
246    ) -> TwigStatus;
247    pub fn twig_document_destroy(doc: *mut TwigDocument);
248    pub fn twig_document_render_html(
249        doc: *mut TwigDocument,
250        out_ptr: *mut *const u8,
251        out_len: *mut usize,
252    ) -> TwigStatus;
253    pub fn twig_document_serialize(
254        doc: *mut TwigDocument,
255        format: c_int,
256        out_ptr: *mut *const u8,
257        out_len: *mut usize,
258    ) -> TwigStatus;
259    pub fn twig_document_ast_json(
260        doc: *mut TwigDocument,
261        out_ptr: *mut *const u8,
262        out_len: *mut usize,
263    ) -> TwigStatus;
264    pub fn twig_document_query(
265        doc: *mut TwigDocument,
266        selector: *const u8,
267        selector_len: usize,
268        out_ptr: *mut *const TwigQueryMatch,
269        out_len: *mut usize,
270    ) -> TwigStatus;
271    pub fn twig_document_node_span(
272        doc: *mut TwigDocument,
273        node_id: u32,
274        out_span: *mut TwigSpan,
275    ) -> TwigStatus;
276    pub fn twig_document_node_content_span(
277        doc: *mut TwigDocument,
278        node_id: u32,
279        out_span: *mut TwigSpan,
280    ) -> TwigStatus;
281    pub fn twig_document_cell_colspan(
282        doc: *mut TwigDocument,
283        node_id: u32,
284        out_colspan: *mut u32,
285    ) -> TwigStatus;
286    pub fn twig_document_cell_rowspan(
287        doc: *mut TwigDocument,
288        node_id: u32,
289        out_rowspan: *mut u32,
290    ) -> TwigStatus;
291    pub fn twig_document_nodes(
292        doc: *mut TwigDocument,
293        out_ptr: *mut *const TwigFlatNode,
294        out_len: *mut usize,
295    ) -> TwigStatus;
296    pub fn twig_document_children(
297        doc: *mut TwigDocument,
298        node_id: u32,
299        out_ptr: *mut *const TwigQueryMatch,
300        out_len: *mut usize,
301    ) -> TwigStatus;
302    pub fn twig_document_subtree(
303        doc: *mut TwigDocument,
304        node_id: u32,
305        out_ptr: *mut *const TwigFlatNode,
306        out_len: *mut usize,
307    ) -> TwigStatus;
308    pub fn twig_document_node_at(
309        doc: *mut TwigDocument,
310        offset: usize,
311        out_match: *mut TwigQueryMatch,
312    ) -> TwigStatus;
313    pub fn twig_document_nodes_at(
314        doc: *mut TwigDocument,
315        offset: usize,
316        out_ptr: *mut *const TwigQueryMatch,
317        out_len: *mut usize,
318    ) -> TwigStatus;
319
320    pub fn twig_editor_create(
321        input: *const u8,
322        input_len: usize,
323        format: c_int,
324        out_editor: *mut *mut TwigEditor,
325    ) -> TwigStatus;
326    pub fn twig_editor_create_ext(
327        input: *const u8,
328        input_len: usize,
329        format: c_int,
330        md_flags: u32,
331        out_editor: *mut *mut TwigEditor,
332    ) -> TwigStatus;
333    pub fn twig_editor_destroy(editor: *mut TwigEditor);
334    pub fn twig_editor_replace(
335        editor: *mut TwigEditor,
336        locator: *const u8,
337        locator_len: usize,
338        text: *const u8,
339        text_len: usize,
340    ) -> TwigStatus;
341    pub fn twig_editor_replace_content(
342        editor: *mut TwigEditor,
343        locator: *const u8,
344        locator_len: usize,
345        text: *const u8,
346        text_len: usize,
347    ) -> TwigStatus;
348    pub fn twig_editor_insert_before(
349        editor: *mut TwigEditor,
350        locator: *const u8,
351        locator_len: usize,
352        text: *const u8,
353        text_len: usize,
354    ) -> TwigStatus;
355    pub fn twig_editor_insert_after(
356        editor: *mut TwigEditor,
357        locator: *const u8,
358        locator_len: usize,
359        text: *const u8,
360        text_len: usize,
361    ) -> TwigStatus;
362    pub fn twig_editor_insert_child(
363        editor: *mut TwigEditor,
364        locator: *const u8,
365        locator_len: usize,
366        child_index: usize,
367        text: *const u8,
368        text_len: usize,
369    ) -> TwigStatus;
370    pub fn twig_editor_delete(
371        editor: *mut TwigEditor,
372        locator: *const u8,
373        locator_len: usize,
374    ) -> TwigStatus;
375    pub fn twig_editor_delete_smart(
376        editor: *mut TwigEditor,
377        locator: *const u8,
378        locator_len: usize,
379    ) -> TwigStatus;
380    pub fn twig_editor_unwrap(
381        editor: *mut TwigEditor,
382        locator: *const u8,
383        locator_len: usize,
384    ) -> TwigStatus;
385    pub fn twig_editor_filter(
386        editor: *mut TwigEditor,
387        drop: *const u8,
388        drop_len: usize,
389        keep: *const u8,
390        keep_len: usize,
391        unwrap_kept: c_int,
392    ) -> TwigStatus;
393    pub fn twig_editor_source(
394        editor: *mut TwigEditor,
395        out_ptr: *mut *const u8,
396        out_len: *mut usize,
397    ) -> TwigStatus;
398    pub fn twig_editor_document(
399        editor: *mut TwigEditor,
400        out_doc: *mut *mut TwigDocument,
401    ) -> TwigStatus;
402    pub fn twig_editor_ast_json(
403        editor: *mut TwigEditor,
404        out_ptr: *mut *const u8,
405        out_len: *mut usize,
406    ) -> TwigStatus;
407    pub fn twig_editor_query(
408        editor: *mut TwigEditor,
409        selector: *const u8,
410        selector_len: usize,
411        out_ptr: *mut *const TwigQueryMatch,
412        out_len: *mut usize,
413    ) -> TwigStatus;
414    pub fn twig_editor_edit_range(
415        editor: *mut TwigEditor,
416        start: usize,
417        end: usize,
418        text: *const u8,
419        text_len: usize,
420        out_change: *mut TwigChange,
421    ) -> TwigStatus;
422    pub fn twig_editor_last_change(
423        editor: *mut TwigEditor,
424        out_change: *mut TwigChange,
425    ) -> TwigStatus;
426    pub fn twig_editor_undo(editor: *mut TwigEditor, out_change: *mut TwigChange) -> TwigStatus;
427    pub fn twig_editor_redo(editor: *mut TwigEditor, out_change: *mut TwigChange) -> TwigStatus;
428    pub fn twig_editor_coalesce_last(editor: *mut TwigEditor) -> TwigStatus;
429    pub fn twig_editor_revision(editor: *mut TwigEditor) -> u64;
430    pub fn twig_editor_dirty_range(editor: *mut TwigEditor, out_span: *mut TwigSpan)
431        -> TwigStatus;
432    pub fn twig_editor_clear_dirty(editor: *mut TwigEditor) -> TwigStatus;
433    pub fn twig_editor_set_caret_blob(
434        editor: *mut TwigEditor,
435        blob_ptr: *const u8,
436        blob_len: usize,
437    ) -> TwigStatus;
438    pub fn twig_editor_caret_blob(
439        editor: *mut TwigEditor,
440        out_ptr: *mut *const u8,
441        out_len: *mut usize,
442    ) -> TwigStatus;
443    pub fn twig_editor_nodes(
444        editor: *mut TwigEditor,
445        out_ptr: *mut *const TwigFlatNode,
446        out_len: *mut usize,
447    ) -> TwigStatus;
448    pub fn twig_editor_child_spans(
449        editor: *mut TwigEditor,
450        node_id: u32,
451        out_ptr: *mut *const TwigQueryMatch,
452        out_len: *mut usize,
453    ) -> TwigStatus;
454    pub fn twig_editor_subtree(
455        editor: *mut TwigEditor,
456        node_id: u32,
457        out_ptr: *mut *const TwigFlatNode,
458        out_len: *mut usize,
459    ) -> TwigStatus;
460    pub fn twig_editor_node_at(
461        editor: *mut TwigEditor,
462        offset: usize,
463        out_match: *mut TwigQueryMatch,
464    ) -> TwigStatus;
465    pub fn twig_editor_nodes_at(
466        editor: *mut TwigEditor,
467        offset: usize,
468        out_ptr: *mut *const TwigQueryMatch,
469        out_len: *mut usize,
470    ) -> TwigStatus;
471    pub fn twig_editor_wrap_range(
472        editor: *mut TwigEditor,
473        start: usize,
474        end: usize,
475        kind: c_int,
476        out_change: *mut TwigChange,
477    ) -> TwigStatus;
478    pub fn twig_editor_toggle_inline(
479        editor: *mut TwigEditor,
480        start: usize,
481        end: usize,
482        kind: c_int,
483        out_change: *mut TwigChange,
484    ) -> TwigStatus;
485    pub fn twig_editor_set_block(
486        editor: *mut TwigEditor,
487        offset: usize,
488        block_kind: c_int,
489        level: u32,
490        out_change: *mut TwigChange,
491    ) -> TwigStatus;
492    pub fn twig_editor_toggle_block_container(
493        editor: *mut TwigEditor,
494        start: usize,
495        end: usize,
496        container_kind: c_int,
497        out_change: *mut TwigChange,
498    ) -> TwigStatus;
499    pub fn twig_editor_renumber_ordered_lists(
500        editor: *mut TwigEditor,
501        offset: usize,
502        out_change: *mut TwigChange,
503    ) -> TwigStatus;
504    pub fn twig_editor_table_edit(
505        editor: *mut TwigEditor,
506        offset: usize,
507        op: c_int,
508        arg: c_int,
509        out_change: *mut TwigChange,
510    ) -> TwigStatus;
511    pub fn twig_editor_insert_link(
512        editor: *mut TwigEditor,
513        start: usize,
514        end: usize,
515        destination: *const u8,
516        destination_len: usize,
517        out_change: *mut TwigChange,
518    ) -> TwigStatus;
519    pub fn twig_editor_insert_image(
520        editor: *mut TwigEditor,
521        start: usize,
522        end: usize,
523        destination: *const u8,
524        destination_len: usize,
525        out_change: *mut TwigChange,
526    ) -> TwigStatus;
527
528    pub fn twig_editor_insert_literal(
529        editor: *mut TwigEditor,
530        offset: usize,
531        text: *const u8,
532        text_len: usize,
533        out_change: *mut TwigChange,
534    ) -> TwigStatus;
535
536    pub fn twig_editor_insert_line_break(
537        editor: *mut TwigEditor,
538        offset: usize,
539        out_change: *mut TwigChange,
540    ) -> TwigStatus;
541
542    pub fn twig_builder_create(out_builder: *mut *mut TwigBuilder) -> TwigStatus;
543    pub fn twig_builder_destroy(builder: *mut TwigBuilder);
544    pub fn twig_builder_add(builder: *mut TwigBuilder, kind: c_int, out_id: *mut u32) -> TwigStatus;
545    pub fn twig_builder_add_text(
546        builder: *mut TwigBuilder,
547        kind: c_int,
548        text: *const u8,
549        text_len: usize,
550        out_id: *mut u32,
551    ) -> TwigStatus;
552    pub fn twig_builder_add_heading(builder: *mut TwigBuilder, level: u32, out_id: *mut u32) -> TwigStatus;
553    pub fn twig_builder_add_code_block(
554        builder: *mut TwigBuilder,
555        lang: *const u8,
556        lang_len: usize,
557        has_lang: c_int,
558        text: *const u8,
559        text_len: usize,
560        out_id: *mut u32,
561    ) -> TwigStatus;
562    pub fn twig_builder_add_raw_block(
563        builder: *mut TwigBuilder,
564        format: *const u8,
565        format_len: usize,
566        text: *const u8,
567        text_len: usize,
568        out_id: *mut u32,
569    ) -> TwigStatus;
570    pub fn twig_builder_add_metadata(
571        builder: *mut TwigBuilder,
572        lang: *const u8,
573        lang_len: usize,
574        text: *const u8,
575        text_len: usize,
576        out_id: *mut u32,
577    ) -> TwigStatus;
578    pub fn twig_builder_add_raw_inline(
579        builder: *mut TwigBuilder,
580        format: *const u8,
581        format_len: usize,
582        text: *const u8,
583        text_len: usize,
584        out_id: *mut u32,
585    ) -> TwigStatus;
586    pub fn twig_builder_add_smart_punctuation(
587        builder: *mut TwigBuilder,
588        punct_kind: c_int,
589        text: *const u8,
590        text_len: usize,
591        out_id: *mut u32,
592    ) -> TwigStatus;
593    pub fn twig_builder_add_link(
594        builder: *mut TwigBuilder,
595        destination: *const u8,
596        destination_len: usize,
597        has_destination: c_int,
598        reference: *const u8,
599        reference_len: usize,
600        has_reference: c_int,
601        out_id: *mut u32,
602    ) -> TwigStatus;
603    pub fn twig_builder_add_image(
604        builder: *mut TwigBuilder,
605        destination: *const u8,
606        destination_len: usize,
607        has_destination: c_int,
608        reference: *const u8,
609        reference_len: usize,
610        has_reference: c_int,
611        out_id: *mut u32,
612    ) -> TwigStatus;
613    pub fn twig_builder_add_directive(
614        builder: *mut TwigBuilder,
615        form: c_int,
616        name: *const u8,
617        name_len: usize,
618        out_id: *mut u32,
619    ) -> TwigStatus;
620    pub fn twig_builder_add_element(
621        builder: *mut TwigBuilder,
622        name: *const u8,
623        name_len: usize,
624        out_id: *mut u32,
625    ) -> TwigStatus;
626    pub fn twig_builder_add_processing_instruction(
627        builder: *mut TwigBuilder,
628        target: *const u8,
629        target_len: usize,
630        data: *const u8,
631        data_len: usize,
632        out_id: *mut u32,
633    ) -> TwigStatus;
634    pub fn twig_builder_add_footnote(
635        builder: *mut TwigBuilder,
636        label: *const u8,
637        label_len: usize,
638        out_id: *mut u32,
639    ) -> TwigStatus;
640    pub fn twig_builder_add_citation(
641        builder: *mut TwigBuilder,
642        label: *const u8,
643        label_len: usize,
644        out_id: *mut u32,
645    ) -> TwigStatus;
646    pub fn twig_builder_add_substitution(
647        builder: *mut TwigBuilder,
648        label: *const u8,
649        label_len: usize,
650        out_id: *mut u32,
651    ) -> TwigStatus;
652    pub fn twig_builder_add_reference(
653        builder: *mut TwigBuilder,
654        label: *const u8,
655        label_len: usize,
656        destination: *const u8,
657        destination_len: usize,
658        out_id: *mut u32,
659    ) -> TwigStatus;
660    pub fn twig_builder_add_bullet_list(
661        builder: *mut TwigBuilder,
662        style: c_int,
663        tight: c_int,
664        out_id: *mut u32,
665    ) -> TwigStatus;
666    pub fn twig_builder_add_ordered_list(
667        builder: *mut TwigBuilder,
668        numbering: c_int,
669        delim: c_int,
670        tight: c_int,
671        start: u32,
672        has_start: c_int,
673        out_id: *mut u32,
674    ) -> TwigStatus;
675    pub fn twig_builder_add_task_list(builder: *mut TwigBuilder, tight: c_int, out_id: *mut u32) -> TwigStatus;
676    pub fn twig_builder_add_task_list_item(builder: *mut TwigBuilder, checked: c_int, out_id: *mut u32) -> TwigStatus;
677    pub fn twig_builder_add_row(builder: *mut TwigBuilder, head: c_int, out_id: *mut u32) -> TwigStatus;
678    pub fn twig_builder_add_cell(builder: *mut TwigBuilder, head: c_int, alignment: c_int, out_id: *mut u32) -> TwigStatus;
679    pub fn twig_builder_add_cell_spanning(
680        builder: *mut TwigBuilder,
681        head: c_int,
682        alignment: c_int,
683        colspan: u32,
684        rowspan: u32,
685        out_id: *mut u32,
686    ) -> TwigStatus;
687    pub fn twig_builder_set_children(
688        builder: *mut TwigBuilder,
689        parent: u32,
690        ids: *const u32,
691        ids_len: usize,
692    ) -> TwigStatus;
693    pub fn twig_builder_set_attrs(
694        builder: *mut TwigBuilder,
695        id: u32,
696        kvs: *const TwigKeyVal,
697        kvs_len: usize,
698    ) -> TwigStatus;
699    pub fn twig_builder_render_html(
700        builder: *mut TwigBuilder,
701        root: u32,
702        out_ptr: *mut *const u8,
703        out_len: *mut usize,
704    ) -> TwigStatus;
705    pub fn twig_builder_serialize(
706        builder: *mut TwigBuilder,
707        root: u32,
708        format: c_int,
709        out_ptr: *mut *const u8,
710        out_len: *mut usize,
711    ) -> TwigStatus;
712    pub fn twig_builder_ast_json(
713        builder: *mut TwigBuilder,
714        root: u32,
715        out_ptr: *mut *const u8,
716        out_len: *mut usize,
717    ) -> TwigStatus;
718    pub fn twig_builder_query(
719        builder: *mut TwigBuilder,
720        root: u32,
721        selector: *const u8,
722        selector_len: usize,
723        out_ptr: *mut *const TwigQueryMatch,
724        out_len: *mut usize,
725    ) -> TwigStatus;
726}