Skip to main content

serde_saphyr/ser/
mod.rs

1//! Single-pass YAML serializer with optional anchors for Rc/Arc/Weak,
2//! order preservation (uses the iterator order of your types), simple
3//! style controls (block strings & flow containers), and special
4//! float handling for NaN/±Inf. No intermediate YAML DOM is built.
5//!
6//! Usage example:
7//!
8//! ```
9//! use serde::Serialize;
10//! use std::rc::Rc;
11//! use serde_saphyr::{to_string, RcAnchor, LitStr, FlowSeq};
12//!
13//! #[derive(Serialize)]
14//! struct Cfg {
15//!     name: String,
16//!     ports: FlowSeq<Vec<u16>>,   // render `[8080, 8081]`
17//!     note: LitStr<'static>,      // render as `|` block
18//!     data: RcAnchor<Vec<i32>>,   // first sight => &a1
19//!     alias: RcAnchor<Vec<i32>>,  // later sight => *a1
20//! }
21//!
22//! fn main() {
23//!     let shared = Rc::new(vec![1,2,3]);
24//!     let cfg = Cfg {
25//!         name: "demo".into(),
26//!         ports: FlowSeq(vec![8080, 8081]),
27//!         note: LitStr("line 1\nline 2"),
28//!         data: RcAnchor(shared.clone()),
29//!         alias: RcAnchor(shared),
30//!     };
31//!     println!("{}", to_string(&cfg).unwrap());
32//! }
33//! ```
34
35use serde_core::ser::Error as _;
36
37pub(crate) mod api;
38pub mod error;
39pub mod options;
40pub(crate) mod quoting;
41mod serializer;
42mod wrapper_impls;
43mod wrapping;
44mod zmij_format;
45
46pub use self::error::Error;
47pub use self::serializer::YamlSerializer;
48#[doc(hidden)]
49pub use self::serializer::{MapSer, SeqSer, StructVariantSer, TupleSer};
50
51/// Result alias.
52pub type Result<T> = std::result::Result<T, Error>;
53
54#[inline]
55fn checked_indentation(indent_step: usize, depth: usize) -> Result<usize> {
56    indent_step
57        .checked_mul(depth)
58        .ok_or_else(|| Error::custom("serializer indentation exceeds usize"))
59}
60
61#[inline]
62fn checked_depth_add(depth: usize, additional_levels: usize) -> Result<usize> {
63    depth
64        .checked_add(additional_levels)
65        .ok_or_else(|| Error::custom("serializer indentation depth exceeds usize"))
66}
67
68pub use crate::long_strings::{FoldStr, FoldString, LitStr, LitString};
69
70// Flow hints and block-string hints: we use newtype-struct names.
71const NAME_TUPLE_ANCHOR: &str = "__yaml_anchor";
72const NAME_TUPLE_WEAK: &str = "__yaml_weak_anchor";
73const NAME_FLOW_SEQ: &str = "__yaml_flow_seq";
74const NAME_FLOW_MAP: &str = "__yaml_flow_map";
75#[cfg(feature = "comments")]
76const NAME_TUPLE_COMMENTED: &str = "__yaml_commented";
77const NAME_TUPLE_TAGGED: &str = "__yaml_tagged";
78const NAME_SPACE_AFTER: &str = "__yaml_space_after";
79const NAME_DOUBLE_QUOTED: &str = "__yaml_double_quoted";
80const NAME_SINGLE_QUOTED: &str = "__yaml_single_quoted";
81const NAME_NULLABLE_TILDE: &str = "__yaml_nullable_tilde";
82
83#[cfg(test)]
84mod tests {
85    use super::{checked_depth_add, checked_indentation};
86
87    #[test]
88    fn indentation_arithmetic_is_checked() {
89        assert_eq!(checked_indentation(64, 2).unwrap(), 128);
90        assert_eq!(
91            checked_indentation(2, usize::MAX).unwrap_err().to_string(),
92            "serializer indentation exceeds usize"
93        );
94        assert_eq!(
95            checked_depth_add(usize::MAX, 1).unwrap_err().to_string(),
96            "serializer indentation depth exceeds usize"
97        );
98        assert_eq!(
99            checked_depth_add(usize::MAX - 1, 2)
100                .unwrap_err()
101                .to_string(),
102            "serializer indentation depth exceeds usize"
103        );
104    }
105}