mod convert;
mod fmt;
mod parse;
mod ser;
mod unescape;
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
#[doc(hidden)]
pub use convert::to_value;
pub use convert::{expr_to_value, value_to_expr};
pub(crate) use convert::{
into_value, synthetic_bool, synthetic_char, synthetic_f32, synthetic_f64, synthetic_integer,
synthetic_map, synthetic_option, synthetic_seq, synthetic_string, synthetic_tuple,
synthetic_unit,
};
#[doc(hidden)]
pub use convert::{synthetic_named_tuple, synthetic_named_unit, synthetic_struct};
pub use fmt::{
CommentMode, CompactTypes, Compaction, FormatConfig, Spacing, format_document, format_expr,
};
pub(crate) use fmt::{ItemTrivia, RonFormatter, SerializeRon, to_ron_string};
pub use parse::{parse_document, parse_document_lossy};
pub use ser::{serialize_document, serialize_document_to};
#[doc(hidden)]
pub use unescape::decode_string;
use crate::error::{Error, Span};
macro_rules! impl_into_owned {
(
$name:ident { $($field:ident : $kind:tt $( ( $($inner:tt)* ) )?),* $(,)? }
) => {
impl $name<'_> {
#[must_use]
pub fn into_owned(self) -> $name<'static> {
$name {
$(
$field: impl_into_owned!(@convert $kind $( ( $($inner)* ) )? ; self.$field),
)*
}
}
}
};
(@convert copy ; $field:expr) => { $field };
(@convert cow ; $field:expr) => { Cow::Owned($field.into_owned()) };
(@convert owned ($ty:ty) ; $field:expr) => { $field.into_owned() };
(@convert vec ($ty:ty) ; $field:expr) => {
$field.into_iter().map(<$ty>::into_owned).collect()
};
(@convert option ($ty:ty) ; $field:expr) => {
$field.map(<$ty>::into_owned)
};
(@convert boxed ($ty:ty) ; $field:expr) => {
Box::new($field.into_owned())
};
(@convert vec_cow ; $field:expr) => {
$field.into_iter().map(|a| Cow::Owned(a.into_owned())).collect()
};
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Trivia<'a> {
pub span: Option<Span>,
pub whitespace: Cow<'a, str>,
pub comments: Vec<Comment<'a>>,
}
impl Trivia<'_> {
#[inline]
#[must_use]
pub fn empty() -> Self {
Self {
span: None,
whitespace: Cow::Borrowed(""),
comments: Vec::new(),
}
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.span.is_none() && self.whitespace.is_empty() && self.comments.is_empty()
}
}
impl_into_owned!(Trivia {
span: copy,
whitespace: cow,
comments: vec(Comment),
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Comment<'a> {
pub span: Span,
pub text: Cow<'a, str>,
pub kind: CommentKind,
}
impl Comment<'_> {
#[must_use]
pub fn content(&self) -> &str {
match self.kind {
CommentKind::Line => self.text.strip_prefix("//").unwrap_or(&self.text),
CommentKind::Block => self
.text
.strip_prefix("/*")
.and_then(|s| s.strip_suffix("*/"))
.unwrap_or(&self.text),
}
}
}
impl_into_owned!(Comment {
span: copy,
text: cow,
kind: copy,
});
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CommentKind {
Line,
Block,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Document<'a> {
pub source: Cow<'a, str>,
pub leading: Trivia<'a>,
pub attributes: Vec<Attribute<'a>>,
pub pre_value: Trivia<'a>,
pub value: Option<Expr<'a>>,
pub trailing: Trivia<'a>,
}
impl_into_owned!(Document {
source: cow,
leading: owned(Trivia),
attributes: vec(Attribute),
pre_value: owned(Trivia),
value: option(Expr),
trailing: owned(Trivia),
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Attribute<'a> {
pub span: Span,
pub leading: Trivia<'a>,
pub name: Cow<'a, str>,
pub content: AttributeContent<'a>,
}
impl_into_owned!(Attribute {
span: copy,
leading: owned(Trivia),
name: cow,
content: owned(AttributeContent),
});
impl Attribute<'_> {
#[must_use]
pub fn synthetic_type(type_path: &str) -> Attribute<'static> {
Attribute {
span: Span::synthetic(),
leading: Trivia::empty(),
name: Cow::Owned("type".to_string()),
content: AttributeContent::Value(Cow::Owned(alloc::format!("\"{type_path}\""))),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AttributeContent<'a> {
None,
Value(Cow<'a, str>),
Args(Vec<Cow<'a, str>>),
}
impl AttributeContent<'_> {
#[must_use]
pub fn into_owned(self) -> AttributeContent<'static> {
match self {
Self::None => AttributeContent::None,
Self::Value(v) => AttributeContent::Value(Cow::Owned(v.into_owned())),
Self::Args(args) => AttributeContent::Args(
args.into_iter()
.map(|a| Cow::Owned(a.into_owned()))
.collect(),
),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expr<'a> {
Unit(UnitExpr),
Bool(BoolExpr),
Char(CharExpr<'a>),
Byte(ByteExpr<'a>),
Number(NumberExpr<'a>),
String(StringExpr<'a>),
Bytes(BytesExpr<'a>),
Option(Box<OptionExpr<'a>>),
Seq(SeqExpr<'a>),
Map(MapExpr<'a>),
Tuple(TupleExpr<'a>),
AnonStruct(AnonStructExpr<'a>),
Struct(StructExpr<'a>),
Error(ErrorExpr),
}
impl Expr<'_> {
#[must_use]
pub fn span(&self) -> &Span {
match self {
Self::Unit(e) => &e.span,
Self::Bool(e) => &e.span,
Self::Char(e) => &e.span,
Self::Byte(e) => &e.span,
Self::Number(e) => &e.span,
Self::String(e) => &e.span,
Self::Bytes(e) => &e.span,
Self::Option(e) => &e.span,
Self::Seq(e) => &e.span,
Self::Map(e) => &e.span,
Self::Tuple(e) => &e.span,
Self::AnonStruct(e) => &e.span,
Self::Struct(e) => &e.span,
Self::Error(e) => &e.span,
}
}
#[must_use]
pub fn into_owned(self) -> Expr<'static> {
match self {
Self::Unit(u) => Expr::Unit(u),
Self::Bool(b) => Expr::Bool(b),
Self::Char(c) => Expr::Char(c.into_owned()),
Self::Byte(b) => Expr::Byte(b.into_owned()),
Self::Number(n) => Expr::Number(n.into_owned()),
Self::String(s) => Expr::String(s.into_owned()),
Self::Bytes(b) => Expr::Bytes(b.into_owned()),
Self::Option(o) => Expr::Option(Box::new(o.into_owned())),
Self::Seq(s) => Expr::Seq(s.into_owned()),
Self::Map(m) => Expr::Map(m.into_owned()),
Self::Tuple(t) => Expr::Tuple(t.into_owned()),
Self::AnonStruct(a) => Expr::AnonStruct(a.into_owned()),
Self::Struct(s) => Expr::Struct(s.into_owned()),
Self::Error(e) => Expr::Error(e),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ErrorExpr {
pub span: Span,
pub error: Error,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnitExpr {
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BoolExpr {
pub span: Span,
pub value: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CharExpr<'a> {
pub span: Span,
pub raw: Cow<'a, str>,
pub value: char,
}
impl_into_owned!(CharExpr {
span: copy,
raw: cow,
value: copy,
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ByteExpr<'a> {
pub span: Span,
pub raw: Cow<'a, str>,
pub value: u8,
}
impl_into_owned!(ByteExpr {
span: copy,
raw: cow,
value: copy,
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NumberExpr<'a> {
pub span: Span,
pub raw: Cow<'a, str>,
pub kind: NumberKind,
}
impl_into_owned!(NumberExpr {
span: copy,
raw: cow,
kind: copy,
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NumberKind {
Integer,
NegativeInteger,
Float,
SpecialFloat,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringExpr<'a> {
pub span: Span,
pub raw: Cow<'a, str>,
pub value: String,
pub kind: StringKind,
}
impl_into_owned!(StringExpr {
span: copy,
raw: cow,
value: copy,
kind: copy,
});
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StringKind {
Regular,
Raw {
hash_count: u8,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BytesExpr<'a> {
pub span: Span,
pub raw: Cow<'a, str>,
pub value: Vec<u8>,
pub kind: BytesKind,
}
impl_into_owned!(BytesExpr {
span: copy,
raw: cow,
value: copy,
kind: copy,
});
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BytesKind {
Regular,
Raw {
hash_count: u8,
},
}
#[derive(Clone, Debug, PartialEq)]
pub struct OptionExpr<'a> {
pub span: Span,
pub value: Option<OptionValue<'a>>,
}
impl_into_owned!(OptionExpr {
span: copy,
value: option(OptionValue),
});
#[derive(Clone, Debug, PartialEq)]
pub struct OptionValue<'a> {
pub open_paren: Span,
pub leading: Trivia<'a>,
pub expr: Expr<'a>,
pub trailing: Trivia<'a>,
pub close_paren: Span,
}
impl_into_owned!(OptionValue {
open_paren: copy,
leading: owned(Trivia),
expr: owned(Expr),
trailing: owned(Trivia),
close_paren: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct SeqExpr<'a> {
pub span: Span,
pub open_bracket: Span,
pub leading: Trivia<'a>,
pub items: Vec<SeqItem<'a>>,
pub trailing: Trivia<'a>,
pub close_bracket: Span,
}
impl_into_owned!(SeqExpr {
span: copy,
open_bracket: copy,
leading: owned(Trivia),
items: vec(SeqItem),
trailing: owned(Trivia),
close_bracket: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct SeqItem<'a> {
pub leading: Trivia<'a>,
pub expr: Expr<'a>,
pub trailing: Trivia<'a>,
pub comma: Option<Span>,
}
impl_into_owned!(SeqItem {
leading: owned(Trivia),
expr: owned(Expr),
trailing: owned(Trivia),
comma: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct MapExpr<'a> {
pub span: Span,
pub open_brace: Span,
pub leading: Trivia<'a>,
pub entries: Vec<MapEntry<'a>>,
pub trailing: Trivia<'a>,
pub close_brace: Span,
}
impl_into_owned!(MapExpr {
span: copy,
open_brace: copy,
leading: owned(Trivia),
entries: vec(MapEntry),
trailing: owned(Trivia),
close_brace: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct MapEntry<'a> {
pub leading: Trivia<'a>,
pub key: Expr<'a>,
pub pre_colon: Trivia<'a>,
pub colon: Span,
pub post_colon: Trivia<'a>,
pub value: Expr<'a>,
pub trailing: Trivia<'a>,
pub comma: Option<Span>,
}
impl_into_owned!(MapEntry {
leading: owned(Trivia),
key: owned(Expr),
pre_colon: owned(Trivia),
colon: copy,
post_colon: owned(Trivia),
value: owned(Expr),
trailing: owned(Trivia),
comma: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct TupleExpr<'a> {
pub span: Span,
pub open_paren: Span,
pub leading: Trivia<'a>,
pub elements: Vec<TupleElement<'a>>,
pub trailing: Trivia<'a>,
pub close_paren: Span,
}
impl_into_owned!(TupleExpr {
span: copy,
open_paren: copy,
leading: owned(Trivia),
elements: vec(TupleElement),
trailing: owned(Trivia),
close_paren: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct AnonStructExpr<'a> {
pub span: Span,
pub open_paren: Span,
pub leading: Trivia<'a>,
pub fields: Vec<StructField<'a>>,
pub trailing: Trivia<'a>,
pub close_paren: Span,
}
impl_into_owned!(AnonStructExpr {
span: copy,
open_paren: copy,
leading: owned(Trivia),
fields: vec(StructField),
trailing: owned(Trivia),
close_paren: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct TupleElement<'a> {
pub leading: Trivia<'a>,
pub expr: Expr<'a>,
pub trailing: Trivia<'a>,
pub comma: Option<Span>,
}
impl_into_owned!(TupleElement {
leading: owned(Trivia),
expr: owned(Expr),
trailing: owned(Trivia),
comma: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct StructExpr<'a> {
pub span: Span,
pub name: Ident<'a>,
pub pre_body: Trivia<'a>,
pub body: Option<StructBody<'a>>,
}
impl_into_owned!(StructExpr {
span: copy,
name: owned(Ident),
pre_body: owned(Trivia),
body: option(StructBody),
});
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ident<'a> {
pub span: Span,
pub name: Cow<'a, str>,
}
impl_into_owned!(Ident {
span: copy,
name: cow,
});
#[derive(Clone, Debug, PartialEq)]
pub enum StructBody<'a> {
Tuple(TupleBody<'a>),
Fields(FieldsBody<'a>),
}
impl StructBody<'_> {
#[must_use]
pub fn into_owned(self) -> StructBody<'static> {
match self {
Self::Tuple(t) => StructBody::Tuple(t.into_owned()),
Self::Fields(f) => StructBody::Fields(f.into_owned()),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TupleBody<'a> {
pub open_paren: Span,
pub leading: Trivia<'a>,
pub elements: Vec<TupleElement<'a>>,
pub trailing: Trivia<'a>,
pub close_paren: Span,
}
impl_into_owned!(TupleBody {
open_paren: copy,
leading: owned(Trivia),
elements: vec(TupleElement),
trailing: owned(Trivia),
close_paren: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct FieldsBody<'a> {
pub open_brace: Span,
pub leading: Trivia<'a>,
pub fields: Vec<StructField<'a>>,
pub trailing: Trivia<'a>,
pub close_brace: Span,
}
impl_into_owned!(FieldsBody {
open_brace: copy,
leading: owned(Trivia),
fields: vec(StructField),
trailing: owned(Trivia),
close_brace: copy,
});
#[derive(Clone, Debug, PartialEq)]
pub struct StructField<'a> {
pub leading: Trivia<'a>,
pub name: Ident<'a>,
pub pre_colon: Trivia<'a>,
pub colon: Span,
pub post_colon: Trivia<'a>,
pub value: Expr<'a>,
pub trailing: Trivia<'a>,
pub comma: Option<Span>,
}
impl_into_owned!(StructField {
leading: owned(Trivia),
name: owned(Ident),
pre_colon: owned(Trivia),
colon: copy,
post_colon: owned(Trivia),
value: owned(Expr),
trailing: owned(Trivia),
comma: copy,
});