use serde_core::ser::{
Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
};
use std::fmt::Write;
use super::helpers::{BoolCapture, StrCapture, UsizeCapture, scalar_key_to_string};
use super::{AnchorId, YamlSerializer};
use crate::ser::options::CommentPosition;
use crate::ser::{Error, Result};
const SIMPLE_KEY_MAX_LEN: usize = 1024;
#[inline]
fn is_simple_key_text(text: &str) -> bool {
text.len() <= SIMPLE_KEY_MAX_LEN || text.chars().count() <= SIMPLE_KEY_MAX_LEN
}
pub struct SeqSer<'a, 'b, W: Write> {
pub(super) ser: &'a mut YamlSerializer<'b, W>,
pub(super) depth: usize,
pub(super) flow: bool,
pub(super) first: bool,
}
impl<'a, 'b, W: Write> SerializeTuple for SeqSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<()> {
SerializeSeq::serialize_element(self, v)
}
fn end(self) -> Result<()> {
SerializeSeq::end(self)
}
}
impl<'a, 'b, W: Write> SerializeSeq for SeqSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<()> {
if self.flow {
if !self.first {
self.ser.out.write_str(", ")?;
}
self.ser.with_in_flow(|s| v.serialize(s))?;
} else {
if self.first && self.ser.pending_space_after_colon {
self.ser.pending_space_after_colon = false;
if !self.ser.at_line_start {
self.ser.newline()?;
}
self.ser.pending_inline_map = false;
}
if !self.first && self.ser.inline_map_after_dash {
self.ser.inline_map_after_dash = false;
}
if self.first && (!self.ser.at_line_start || self.ser.pending_inline_map) {
} else {
self.ser.write_indent(self.depth)?;
}
self.ser.out.write_str("- ")?;
self.ser.at_line_start = false;
if self.first && self.ser.inline_map_after_dash {
self.ser.inline_map_after_dash = false;
}
self.ser.after_dash_depth = Some(self.depth);
self.ser.pending_inline_map = true;
self.ser.last_value_was_block = false;
v.serialize(&mut *self.ser)?;
}
self.first = false;
Ok(())
}
fn end(self) -> Result<()> {
if self.flow {
self.ser.out.write_str("]")?;
if self.ser.in_flow == 0 {
self.ser.newline()?;
}
} else if self.first {
if self.ser.empty_as_braces {
if self.ser.pending_space_after_colon {
self.ser.out.write_str(" ")?;
self.ser.pending_space_after_colon = false;
} else if self.ser.at_line_start {
self.ser.write_indent(self.depth)?;
}
self.ser.out.write_str("[]")?;
self.ser.newline()?;
} else {
self.ser.pending_space_after_colon = false;
self.ser.newline()?;
}
} else {
self.ser.last_value_was_block = true;
self.ser.pending_inline_map = false;
self.ser.after_dash_depth = None;
self.ser.inline_map_after_dash = false;
}
Ok(())
}
}
pub enum TupleSer<'a, 'b, W: Write> {
Seq(SeqSer<'a, 'b, W>),
Special(SpecialTupleSer<'a, 'b, W>),
}
pub struct SpecialTupleSer<'a, 'b, W: Write> {
ser: &'a mut YamlSerializer<'b, W>,
kind: TupleKind,
idx: usize,
weak_anchor_ptr: usize,
strong_alias_id: Option<AnchorId>,
weak_present: bool,
skip_third: bool,
weak_alias_id: Option<AnchorId>,
comment_text: Option<String>,
}
enum TupleKind {
AnchorStrong, AnchorWeak, Commented, }
impl<'a, 'b, W: Write> TupleSer<'a, 'b, W> {
pub(super) fn anchor_strong(ser: &'a mut YamlSerializer<'b, W>) -> Self {
TupleSer::Special(SpecialTupleSer::new(ser, TupleKind::AnchorStrong))
}
pub(super) fn anchor_weak(ser: &'a mut YamlSerializer<'b, W>) -> Self {
TupleSer::Special(SpecialTupleSer::new(ser, TupleKind::AnchorWeak))
}
pub(super) fn commented(ser: &'a mut YamlSerializer<'b, W>) -> Self {
TupleSer::Special(SpecialTupleSer::new(ser, TupleKind::Commented))
}
}
impl<'a, 'b, W: Write> SpecialTupleSer<'a, 'b, W> {
fn new(ser: &'a mut YamlSerializer<'b, W>, kind: TupleKind) -> Self {
Self {
ser,
kind,
idx: 0,
weak_anchor_ptr: 0,
strong_alias_id: None,
weak_present: false,
skip_third: false,
weak_alias_id: None,
comment_text: None,
}
}
}
impl<'a, 'b, W: Write> SerializeTupleStruct for TupleSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
match self {
TupleSer::Seq(seq) => SerializeSeq::serialize_element(seq, value),
TupleSer::Special(s) => s.serialize_field(value),
}
}
fn end(self) -> Result<()> {
match self {
TupleSer::Seq(seq) => SerializeSeq::end(seq),
TupleSer::Special(s) => s.end(),
}
}
}
impl<'a, 'b, W: Write> SpecialTupleSer<'a, 'b, W> {
fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
match self.kind {
TupleKind::AnchorStrong => {
match self.idx {
0 => {
let mut cap = UsizeCapture::default();
value.serialize(&mut cap)?;
let ptr = cap.finish()?;
let (id, fresh) = self.ser.alloc_anchor_for(ptr);
if fresh {
self.ser.pending_anchor_id = Some(id); self.strong_alias_id = None;
} else {
self.strong_alias_id = Some(id); }
}
1 => {
if let Some(id) = self.strong_alias_id.take() {
self.ser.write_alias_id(id)?;
} else {
value.serialize(&mut *self.ser)?;
}
}
_ => return Err(Error::unexpected("unexpected field in __yaml_anchor")),
}
}
TupleKind::AnchorWeak => {
match self.idx {
0 => {
let mut cap = UsizeCapture::default();
value.serialize(&mut cap)?;
let ptr = cap.finish()?;
self.weak_anchor_ptr = ptr;
}
1 => {
let mut bc = BoolCapture::default();
value.serialize(&mut bc)?;
self.weak_present = bc.finish()?;
if !self.weak_present {
if self.ser.at_line_start {
self.ser.write_indent(self.ser.depth)?;
}
self.ser.out.write_str("null")?;
self.ser.write_end_of_scalar()?;
self.skip_third = true;
} else {
let ptr = self.weak_anchor_ptr;
let (id, fresh) = self.ser.alloc_anchor_for(ptr);
if fresh {
self.ser.pending_anchor_id = Some(id); self.weak_alias_id = None;
} else {
self.weak_alias_id = Some(id); }
}
}
2 => {
if self.skip_third {
} else if let Some(id) = self.weak_alias_id.take() {
self.ser.write_alias_id(id)?;
} else {
value.serialize(&mut *self.ser)?;
}
}
_ => return Err(Error::unexpected("unexpected field in __yaml_weak_anchor")),
}
}
TupleKind::Commented => {
match self.idx {
0 => {
let mut sc = StrCapture::default();
value.serialize(&mut sc)?;
self.comment_text = Some(sc.finish()?);
}
1 => {
let comment = self.comment_text.take().unwrap_or_default();
let sanitized = YamlSerializer::<W>::sanitize_comment_text(&comment);
match self.ser.comment_position {
CommentPosition::Inline => {
if self.ser.in_flow == 0 && !sanitized.is_empty() {
self.ser.pending_inline_comment = Some(sanitized);
}
value.serialize(&mut *self.ser)?;
self.ser.pending_inline_comment = None;
}
CommentPosition::Above => {
let saved_depth = self.ser.depth;
let target_depth = self.ser.write_above_comment(&sanitized)?;
if let Some(depth) = target_depth {
self.ser.depth = depth;
}
let result = value.serialize(&mut *self.ser);
self.ser.depth = saved_depth;
result?;
self.ser.pending_inline_comment = None;
}
}
}
_ => return Err(Error::unexpected("unexpected field in __yaml_commented")),
}
}
}
self.idx += 1;
Ok(())
}
fn end(self) -> Result<()> {
Ok(())
}
}
impl<'a, 'b, W: Write> SerializeTupleVariant for SeqSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<()> {
SerializeSeq::end(self)
}
}
pub struct MapSer<'a, 'b, W: Write> {
pub(super) ser: &'a mut YamlSerializer<'b, W>,
pub(super) depth: usize,
pub(super) flow: bool,
pub(super) first: bool,
pub(super) last_key_complex: bool,
pub(super) align_after_dash: bool,
pub(super) inline_value_start: bool,
}
impl<'a, 'b, W: Write> MapSer<'a, 'b, W> {
fn write_simple_key(&mut self, text: &str) -> Result<()> {
if self.align_after_dash && self.ser.at_line_start {
let base = self.depth.saturating_sub(1);
for _ in 0..self.ser.indent_step * base {
self.ser.out.write_char(' ')?;
}
self.ser.out.write_str(" ")?; self.ser.at_line_start = false;
} else {
self.ser.write_indent(self.depth)?;
}
self.ser.out.write_str(text)?;
self.ser.out.write_str(":")?;
self.ser.pending_space_after_colon = true;
self.ser.at_line_start = false;
self.last_key_complex = false;
Ok(())
}
fn write_explicit_scalar_key(&mut self, text: &str) -> Result<()> {
self.ser.write_indent(self.depth)?;
self.ser.out.write_str("? ")?;
self.ser.out.write_str(text)?;
self.ser.newline()?;
self.last_key_complex = true;
Ok(())
}
fn write_explicit_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
self.ser.write_anchor_for_complex_node()?;
self.ser.write_indent(self.depth)?;
self.ser.out.write_str("? ")?;
self.ser.at_line_start = false;
let saved_depth = self.ser.depth;
let saved_current_map_depth = self.ser.current_map_depth;
let saved_pending_inline_map = self.ser.pending_inline_map;
let saved_inline_map_after_dash = self.ser.inline_map_after_dash;
let saved_after_dash_depth = self.ser.after_dash_depth;
self.ser.pending_inline_map = true;
self.ser.depth = self.depth;
self.ser.current_map_depth = Some(self.depth);
self.ser.after_dash_depth = None;
key.serialize(&mut *self.ser)?;
self.ser.depth = saved_depth;
self.ser.current_map_depth = saved_current_map_depth;
self.ser.pending_inline_map = saved_pending_inline_map;
self.ser.inline_map_after_dash = saved_inline_map_after_dash;
self.ser.after_dash_depth = saved_after_dash_depth;
self.ser.last_value_was_block = false;
self.last_key_complex = true;
Ok(())
}
}
impl<'a, 'b, W: Write> SerializeMap for MapSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
if self.flow {
if !self.first {
self.ser.out.write_str(", ")?;
}
let text = scalar_key_to_string(key, self.ser.yaml_12)?;
if is_simple_key_text(&text) {
self.ser.out.write_str(&text)?;
self.ser.out.write_str(": ")?;
} else {
self.ser.out.write_str("? ")?;
self.ser.out.write_str(&text)?;
self.ser.out.write_str(" : ")?;
}
self.ser.at_line_start = false;
self.last_key_complex = false;
} else {
if self.inline_value_start {
if self.ser.pending_space_after_colon {
self.ser.pending_space_after_colon = false;
}
if !self.ser.at_line_start {
self.ser.newline()?;
}
self.inline_value_start = false;
} else if !self.ser.at_line_start {
self.ser.write_space_if_pending()?;
}
self.ser.after_dash_depth = None;
self.ser.pending_inline_map = false;
self.ser.last_value_was_block = false;
match scalar_key_to_string(key, self.ser.yaml_12) {
Ok(text) if is_simple_key_text(&text) => {
self.write_simple_key(&text)?;
}
Ok(text) => self.write_explicit_scalar_key(&text)?,
Err(Error::Unexpected { msg }) if msg == "non-scalar key" => {
self.write_explicit_key(key)?;
}
Err(e) => return Err(e),
}
}
Ok(())
}
fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
if self.flow {
self.ser.with_in_flow(|s| value.serialize(s))?;
} else {
let saved_pending_inline_map = self.ser.pending_inline_map;
let saved_depth = self.ser.depth;
if self.last_key_complex {
if self.align_after_dash && self.ser.at_line_start {
let base = self.depth.saturating_sub(1);
for _ in 0..self.ser.indent_step * base {
self.ser.out.write_char(' ')?;
}
self.ser.out.write_str(" ")?;
self.ser.at_line_start = false;
} else {
self.ser.write_indent(self.depth)?;
}
self.ser.out.write_str(":")?;
self.ser.pending_space_after_colon = true;
self.ser.pending_inline_map = true;
self.ser.at_line_start = false;
self.ser.depth = self.depth;
}
let prev_map_depth = self.ser.current_map_depth.replace(self.depth);
let result = value.serialize(&mut *self.ser);
self.ser.current_map_depth = prev_map_depth;
self.ser.pending_inline_map = saved_pending_inline_map;
if self.last_key_complex {
self.ser.depth = saved_depth;
self.last_key_complex = false;
}
result?;
}
self.first = false;
Ok(())
}
fn end(self) -> Result<()> {
if self.flow {
self.ser.out.write_str("}")?;
if self.ser.in_flow == 0 {
self.ser.newline()?;
}
} else if self.first {
if self.ser.empty_as_braces {
if self.ser.pending_space_after_colon {
self.ser.out.write_str(" ")?;
self.ser.pending_space_after_colon = false;
}
if self.ser.at_line_start {
if self.align_after_dash {
let base = self.depth.saturating_sub(1);
for _ in 0..self.ser.indent_step * base {
self.ser.out.write_char(' ')?;
}
self.ser.out.write_str(" ")?; self.ser.at_line_start = false;
} else {
self.ser.write_indent(self.depth)?;
}
}
self.ser.out.write_str("{}")?;
self.ser.newline()?;
} else {
self.ser.newline()?;
}
} else {
self.ser.last_value_was_block = true;
}
Ok(())
}
}
impl<'a, 'b, W: Write> SerializeStruct for MapSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(
&mut self,
key: &'static str,
value: &T,
) -> Result<()> {
SerializeMap::serialize_key(self, &key)?;
SerializeMap::serialize_value(self, value)
}
fn end(self) -> Result<()> {
SerializeMap::end(self)
}
}
pub struct StructVariantSer<'a, 'b, W: Write> {
pub(super) ser: &'a mut YamlSerializer<'b, W>,
pub(super) depth: usize,
}
impl<'a, 'b, W: Write> SerializeStructVariant for StructVariantSer<'a, 'b, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(
&mut self,
key: &'static str,
value: &T,
) -> Result<()> {
let text = scalar_key_to_string(&key, self.ser.yaml_12)?;
self.ser.write_indent(self.depth)?;
self.ser.out.write_str(&text)?;
self.ser.out.write_str(":")?;
self.ser.pending_space_after_colon = true;
self.ser.at_line_start = false;
let prev_map_depth = self.ser.current_map_depth.replace(self.depth);
let result = value.serialize(&mut *self.ser);
self.ser.current_map_depth = prev_map_depth;
result
}
fn end(self) -> Result<()> {
Ok(())
}
}