ron2/ast/
mod.rs

1//! AST types for RON documents with copy-on-write semantics.
2//!
3//! This module provides a complete AST representation that preserves:
4//! - Original source text via `Cow` (zero-copy when borrowed, owned when mutated)
5//! - Trivia (whitespace and comments) attached to nodes
6//! - Span information for all nodes
7//!
8//! The AST uses `Cow<'a, str>` for all string data, enabling:
9//! - Zero-copy parsing (strings borrow from source)
10//! - In-place mutation (strings become owned on write)
11//! - Single serializer implementation for both cases
12//!
13//! # Example
14//!
15//! ```
16//! use ron2::ast::parse_document;
17//!
18//! // Parse a RON document into an AST (zero-copy)
19//! let source = "// comment\n42";
20//! let doc = parse_document(source).unwrap();
21//! assert!(doc.value.is_some());
22//! ```
23//!
24//! # Mutation Example
25//!
26//! ```
27//! use ron2::ast::parse_document;
28//! use std::borrow::Cow;
29//!
30//! let source = "Config(name: \"old\")";
31//! let mut doc = parse_document(source).unwrap();
32//!
33//! // Convert to owned for mutation (can outlive source)
34//! let mut owned = doc.into_owned();
35//! ```
36
37mod convert;
38mod fmt;
39mod parse;
40mod ser;
41mod unescape;
42
43use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
44
45pub use convert::{
46    expr_into_value, expr_to_value, into_value, synthetic_bool, synthetic_char, synthetic_f32,
47    synthetic_f64, synthetic_integer, synthetic_map, synthetic_named_tuple, synthetic_named_unit,
48    synthetic_option, synthetic_seq, synthetic_string, synthetic_struct, synthetic_tuple,
49    synthetic_unit, to_value, value_to_expr,
50};
51pub use fmt::{
52    CommentMode, CompactTypes, Compaction, FormatConfig, ItemTrivia, RonFormatter, SerializeRon,
53    Spacing, format_document, format_expr, to_ron_string, to_ron_string_with,
54};
55pub use parse::{parse_document, parse_document_lossy};
56pub use ser::{serialize_document, serialize_document_to};
57
58use crate::error::{Error, Span};
59
60// ============================================================================
61// into_owned() macro
62// ============================================================================
63
64/// Macro to generate `into_owned()` implementations for AST types.
65///
66/// Field kinds:
67/// - `copy` - Field is Copy, passed through unchanged
68/// - `cow` - Field is `Cow<'a, str>`, converted via `Cow::Owned(f.into_owned())`
69/// - `owned(T)` - Field has `into_owned()` method, call it
70/// - `vec(T)` - Field is `Vec<T>` where T has `into_owned()`
71/// - `option(T)` - Field is `Option<T>` where T has `into_owned()`
72/// - `boxed(T)` - Field is `Box<T>` where T has `into_owned()`
73/// - `vec_cow` - Field is `Vec<Cow<'a, str>>`
74macro_rules! impl_into_owned {
75    (
76        $name:ident { $($field:ident : $kind:tt $( ( $($inner:tt)* ) )?),* $(,)? }
77    ) => {
78        impl $name<'_> {
79            /// Converts to an owned version with `'static` lifetime.
80            #[must_use]
81            pub fn into_owned(self) -> $name<'static> {
82                $name {
83                    $(
84                        $field: impl_into_owned!(@convert $kind $( ( $($inner)* ) )? ; self.$field),
85                    )*
86                }
87            }
88        }
89    };
90
91    // Field conversion rules
92    (@convert copy ; $field:expr) => { $field };
93    (@convert cow ; $field:expr) => { Cow::Owned($field.into_owned()) };
94    (@convert owned ($ty:ty) ; $field:expr) => { $field.into_owned() };
95    (@convert vec ($ty:ty) ; $field:expr) => {
96        $field.into_iter().map(<$ty>::into_owned).collect()
97    };
98    (@convert option ($ty:ty) ; $field:expr) => {
99        $field.map(<$ty>::into_owned)
100    };
101    (@convert boxed ($ty:ty) ; $field:expr) => {
102        Box::new($field.into_owned())
103    };
104    (@convert vec_cow ; $field:expr) => {
105        $field.into_iter().map(|a| Cow::Owned(a.into_owned())).collect()
106    };
107}
108
109// ============================================================================
110// Trivia (whitespace and comments)
111// ============================================================================
112
113/// Trivia represents non-semantic content: whitespace and comments.
114///
115/// Trivia is attached to AST nodes to preserve formatting information
116/// for round-tripping and LSP features.
117///
118/// Uses `Cow` for copy-on-write semantics - borrowed when parsed, owned when mutated.
119#[derive(Clone, Debug, Default, PartialEq, Eq)]
120pub struct Trivia<'a> {
121    /// The span covering all trivia content.
122    pub span: Option<Span>,
123    /// The raw whitespace text (for exact round-tripping).
124    /// This includes all characters between tokens that aren't comments.
125    pub whitespace: Cow<'a, str>,
126    /// Comments within this trivia section.
127    pub comments: Vec<Comment<'a>>,
128}
129
130impl Trivia<'_> {
131    /// Creates empty trivia with no comments or whitespace.
132    #[inline]
133    #[must_use]
134    pub fn empty() -> Self {
135        Self {
136            span: None,
137            whitespace: Cow::Borrowed(""),
138            comments: Vec::new(),
139        }
140    }
141
142    /// Returns true if this trivia contains no content.
143    #[inline]
144    #[must_use]
145    pub fn is_empty(&self) -> bool {
146        self.span.is_none() && self.whitespace.is_empty() && self.comments.is_empty()
147    }
148}
149
150impl_into_owned!(Trivia {
151    span: copy,
152    whitespace: cow,
153    comments: vec(Comment),
154});
155
156/// A comment in the source code.
157#[derive(Clone, Debug, PartialEq, Eq)]
158pub struct Comment<'a> {
159    /// The span of the comment including delimiters.
160    pub span: Span,
161    /// The comment text including delimiters (`//` or `/* */`).
162    /// This is the raw source text for exact round-tripping.
163    pub text: Cow<'a, str>,
164    /// The kind of comment.
165    pub kind: CommentKind,
166}
167
168impl Comment<'_> {
169    /// Returns the comment content without delimiters.
170    ///
171    /// For line comments, this strips the leading `//`.
172    /// For block comments, this strips `/*` and `*/`.
173    #[must_use]
174    pub fn content(&self) -> &str {
175        match self.kind {
176            CommentKind::Line => self.text.strip_prefix("//").unwrap_or(&self.text),
177            CommentKind::Block => self
178                .text
179                .strip_prefix("/*")
180                .and_then(|s| s.strip_suffix("*/"))
181                .unwrap_or(&self.text),
182        }
183    }
184}
185
186impl_into_owned!(Comment {
187    span: copy,
188    text: cow,
189    kind: copy,
190});
191
192/// The kind of comment.
193#[derive(Clone, Copy, Debug, PartialEq, Eq)]
194pub enum CommentKind {
195    /// A line comment starting with `//`.
196    Line,
197    /// A block comment delimited by `/*` and `*/`.
198    Block,
199}
200
201// ============================================================================
202// Document (root)
203// ============================================================================
204
205/// A complete RON document.
206///
207/// This is the root of the AST, containing the source text,
208/// any inner attributes, and the main value expression.
209///
210/// Documents may be empty (containing only comments/whitespace),
211/// in which case `value` is `None`.
212#[derive(Clone, Debug, PartialEq)]
213pub struct Document<'a> {
214    /// The original source text (for zero-copy access).
215    pub source: Cow<'a, str>,
216    /// Leading trivia before any content.
217    pub leading: Trivia<'a>,
218    /// Inner attributes (`#![...]`).
219    pub attributes: Vec<Attribute<'a>>,
220    /// Trivia between attributes/leading and the value.
221    pub pre_value: Trivia<'a>,
222    /// The main value expression, if present.
223    /// This is `None` for documents containing only comments/whitespace.
224    pub value: Option<Expr<'a>>,
225    /// Trailing trivia after the value.
226    pub trailing: Trivia<'a>,
227}
228
229impl_into_owned!(Document {
230    source: cow,
231    leading: owned(Trivia),
232    attributes: vec(Attribute),
233    pre_value: owned(Trivia),
234    value: option(Expr),
235    trailing: owned(Trivia),
236});
237
238// ============================================================================
239// Attributes
240// ============================================================================
241
242/// An inner attribute (`#![name]`, `#![name = "value"]`, or `#![name(args)]`).
243///
244/// Attributes provide metadata about the RON document, such as
245/// the expected Rust type, schema path, or enabled extensions.
246#[derive(Clone, Debug, PartialEq, Eq)]
247pub struct Attribute<'a> {
248    /// The span of the entire attribute.
249    pub span: Span,
250    /// Leading trivia before this attribute.
251    pub leading: Trivia<'a>,
252    /// The attribute name (e.g., "type", "schema", "enable").
253    pub name: Cow<'a, str>,
254    /// The attribute content.
255    pub content: AttributeContent<'a>,
256}
257
258impl_into_owned!(Attribute {
259    span: copy,
260    leading: owned(Trivia),
261    name: cow,
262    content: owned(AttributeContent),
263});
264
265impl Attribute<'_> {
266    /// Create a synthetic `#![type = "..."]` attribute.
267    ///
268    /// This is useful when constructing documents programmatically.
269    /// The created attribute has synthetic spans (line 0, column 0).
270    #[must_use]
271    pub fn synthetic_type(type_path: &str) -> Attribute<'static> {
272        Attribute {
273            span: Span::synthetic(),
274            leading: Trivia::empty(),
275            name: Cow::Owned("type".to_string()),
276            content: AttributeContent::Value(Cow::Owned(alloc::format!("\"{type_path}\""))),
277        }
278    }
279}
280
281/// The content of an attribute after the name.
282#[derive(Clone, Debug, PartialEq, Eq)]
283pub enum AttributeContent<'a> {
284    /// No content: `#![name]`
285    None,
286    /// Equals value: `#![name = "value"]`
287    Value(Cow<'a, str>),
288    /// Parenthesized arguments: `#![enable(implicit_some, unwrap_newtypes)]`
289    Args(Vec<Cow<'a, str>>),
290}
291
292impl AttributeContent<'_> {
293    /// Converts this content to an owned version with `'static` lifetime.
294    #[must_use]
295    pub fn into_owned(self) -> AttributeContent<'static> {
296        match self {
297            Self::None => AttributeContent::None,
298            Self::Value(v) => AttributeContent::Value(Cow::Owned(v.into_owned())),
299            Self::Args(args) => AttributeContent::Args(
300                args.into_iter()
301                    .map(|a| Cow::Owned(a.into_owned()))
302                    .collect(),
303            ),
304        }
305    }
306}
307
308// ============================================================================
309// Expressions
310// ============================================================================
311
312/// An expression representing any RON value.
313#[derive(Clone, Debug, PartialEq)]
314pub enum Expr<'a> {
315    /// Unit value: `()`.
316    Unit(UnitExpr),
317    /// Boolean value: `true` or `false`.
318    Bool(BoolExpr),
319    /// Character literal: `'a'`.
320    Char(CharExpr<'a>),
321    /// Byte literal: `b'x'`.
322    Byte(ByteExpr<'a>),
323    /// Numeric literal: `42`, `3.14`, `0xFF`, `1_000`.
324    Number(NumberExpr<'a>),
325    /// String literal: `"hello"` or `r#"raw"#`.
326    String(StringExpr<'a>),
327    /// Byte string literal: `b"bytes"` or `br#"raw"#`.
328    Bytes(BytesExpr<'a>),
329    /// Option value: `None` or `Some(value)`.
330    Option(Box<OptionExpr<'a>>),
331    /// Sequence: `[a, b, c]`.
332    Seq(SeqExpr<'a>),
333    /// Map: `{key: value, ...}`.
334    Map(MapExpr<'a>),
335    /// Tuple: `(a, b, c)`.
336    Tuple(TupleExpr<'a>),
337    /// Anonymous struct: `(field: value, ...)`.
338    AnonStruct(AnonStructExpr<'a>),
339    /// Named struct: `Name(...)` or `Name { ... }`.
340    Struct(StructExpr<'a>),
341    /// Placeholder expression produced during lossy parsing.
342    Error(ErrorExpr),
343}
344
345impl Expr<'_> {
346    /// Returns the span of this expression.
347    #[must_use]
348    pub fn span(&self) -> &Span {
349        match self {
350            Self::Unit(e) => &e.span,
351            Self::Bool(e) => &e.span,
352            Self::Char(e) => &e.span,
353            Self::Byte(e) => &e.span,
354            Self::Number(e) => &e.span,
355            Self::String(e) => &e.span,
356            Self::Bytes(e) => &e.span,
357            Self::Option(e) => &e.span,
358            Self::Seq(e) => &e.span,
359            Self::Map(e) => &e.span,
360            Self::Tuple(e) => &e.span,
361            Self::AnonStruct(e) => &e.span,
362            Self::Struct(e) => &e.span,
363            Self::Error(e) => &e.span,
364        }
365    }
366
367    /// Converts this expression to an owned version with `'static` lifetime.
368    #[must_use]
369    pub fn into_owned(self) -> Expr<'static> {
370        match self {
371            Self::Unit(u) => Expr::Unit(u),
372            Self::Bool(b) => Expr::Bool(b),
373            Self::Char(c) => Expr::Char(c.into_owned()),
374            Self::Byte(b) => Expr::Byte(b.into_owned()),
375            Self::Number(n) => Expr::Number(n.into_owned()),
376            Self::String(s) => Expr::String(s.into_owned()),
377            Self::Bytes(b) => Expr::Bytes(b.into_owned()),
378            Self::Option(o) => Expr::Option(Box::new(o.into_owned())),
379            Self::Seq(s) => Expr::Seq(s.into_owned()),
380            Self::Map(m) => Expr::Map(m.into_owned()),
381            Self::Tuple(t) => Expr::Tuple(t.into_owned()),
382            Self::AnonStruct(a) => Expr::AnonStruct(a.into_owned()),
383            Self::Struct(s) => Expr::Struct(s.into_owned()),
384            Self::Error(e) => Expr::Error(e),
385        }
386    }
387}
388
389/// Error placeholder used by lossy parsing for invalid expressions.
390#[derive(Clone, Debug, PartialEq, Eq)]
391pub struct ErrorExpr {
392    /// Span covering the invalid expression.
393    pub span: Span,
394    /// The parsing error captured at this location.
395    pub error: Error,
396}
397
398// ============================================================================
399// Primitive expressions
400// ============================================================================
401
402/// Unit expression: `()`.
403#[derive(Clone, Debug, PartialEq, Eq)]
404pub struct UnitExpr {
405    /// The span of `()`.
406    pub span: Span,
407}
408
409/// Boolean expression: `true` or `false`.
410#[derive(Clone, Debug, PartialEq, Eq)]
411pub struct BoolExpr {
412    /// The span of the boolean literal.
413    pub span: Span,
414    /// The parsed boolean value.
415    pub value: bool,
416}
417
418/// Character expression: `'a'`, `'\n'`, `'\x00'`, `'\u{1F600}'`.
419#[derive(Clone, Debug, PartialEq, Eq)]
420pub struct CharExpr<'a> {
421    /// The span of the character literal including quotes.
422    pub span: Span,
423    /// The raw source text (includes quotes).
424    pub raw: Cow<'a, str>,
425    /// The parsed character value.
426    pub value: char,
427}
428
429impl_into_owned!(CharExpr {
430    span: copy,
431    raw: cow,
432    value: copy,
433});
434
435/// Byte literal expression: `b'x'`, `b'\n'`, `b'\x00'`.
436#[derive(Clone, Debug, PartialEq, Eq)]
437pub struct ByteExpr<'a> {
438    /// The span of the byte literal including `b` prefix and quotes.
439    pub span: Span,
440    /// The raw source text (includes `b` prefix and quotes).
441    pub raw: Cow<'a, str>,
442    /// The parsed byte value.
443    pub value: u8,
444}
445
446impl_into_owned!(ByteExpr {
447    span: copy,
448    raw: cow,
449    value: copy,
450});
451
452/// Numeric expression: `42`, `3.14`, `0xFF`, `0b1010`, `0o777`, `1_000`.
453///
454/// The raw text is preserved to maintain the original format
455/// (hex, binary, octal, underscores, etc.).
456#[derive(Clone, Debug, PartialEq, Eq)]
457pub struct NumberExpr<'a> {
458    /// The span of the number literal.
459    pub span: Span,
460    /// The raw source text (preserves format like `0xFF`, `1_000`).
461    pub raw: Cow<'a, str>,
462    /// The parsed numeric kind, if available.
463    pub kind: NumberKind,
464}
465
466impl_into_owned!(NumberExpr {
467    span: copy,
468    raw: cow,
469    kind: copy,
470});
471
472/// The kind of number parsed.
473#[derive(Clone, Debug, PartialEq, Eq)]
474pub enum NumberKind {
475    /// A positive integer.
476    Integer,
477    /// A negative integer.
478    NegativeInteger,
479    /// A floating-point number.
480    Float,
481    /// Special float values: `inf`, `-inf`, `NaN`.
482    SpecialFloat,
483}
484
485/// String expression: `"hello"`, `"with\nescape"`, `r#"raw"#`.
486#[derive(Clone, Debug, PartialEq, Eq)]
487pub struct StringExpr<'a> {
488    /// The span of the string literal including quotes.
489    pub span: Span,
490    /// The raw source text (includes quotes and any `r#` prefix).
491    pub raw: Cow<'a, str>,
492    /// The parsed string value (with escapes processed).
493    pub value: String,
494    /// The kind of string literal.
495    pub kind: StringKind,
496}
497
498impl_into_owned!(StringExpr {
499    span: copy,
500    raw: cow,
501    value: copy,
502    kind: copy,
503});
504
505/// The kind of string literal.
506#[derive(Clone, Copy, Debug, PartialEq, Eq)]
507pub enum StringKind {
508    /// A regular quoted string: `"hello"`.
509    Regular,
510    /// A raw string: `r"raw"` or `r#"raw"#`.
511    Raw {
512        /// Number of `#` characters used.
513        hash_count: u8,
514    },
515}
516
517/// Byte string expression: `b"bytes"`, `br#"raw"#`.
518#[derive(Clone, Debug, PartialEq, Eq)]
519pub struct BytesExpr<'a> {
520    /// The span of the byte string literal including prefix and quotes.
521    pub span: Span,
522    /// The raw source text.
523    pub raw: Cow<'a, str>,
524    /// The parsed byte values.
525    pub value: Vec<u8>,
526    /// The kind of byte string literal.
527    pub kind: BytesKind,
528}
529
530impl_into_owned!(BytesExpr {
531    span: copy,
532    raw: cow,
533    value: copy,
534    kind: copy,
535});
536
537/// The kind of byte string literal.
538#[derive(Clone, Copy, Debug, PartialEq, Eq)]
539pub enum BytesKind {
540    /// A regular byte string: `b"bytes"`.
541    Regular,
542    /// A raw byte string: `br"raw"` or `br#"raw"#`.
543    Raw {
544        /// Number of `#` characters used.
545        hash_count: u8,
546    },
547}
548
549// ============================================================================
550// Option expression
551// ============================================================================
552
553/// Option expression: `None` or `Some(value)`.
554#[derive(Clone, Debug, PartialEq)]
555pub struct OptionExpr<'a> {
556    /// The span of the entire option expression.
557    pub span: Span,
558    /// The value, if `Some`.
559    pub value: Option<OptionValue<'a>>,
560}
561
562impl_into_owned!(OptionExpr {
563    span: copy,
564    value: option(OptionValue),
565});
566
567/// The inner value of a `Some(...)` expression.
568#[derive(Clone, Debug, PartialEq)]
569pub struct OptionValue<'a> {
570    /// Span of the opening parenthesis.
571    pub open_paren: Span,
572    /// Leading trivia before the inner value.
573    pub leading: Trivia<'a>,
574    /// The inner expression.
575    pub expr: Expr<'a>,
576    /// Trailing trivia after the inner value.
577    pub trailing: Trivia<'a>,
578    /// Span of the closing parenthesis.
579    pub close_paren: Span,
580}
581
582impl_into_owned!(OptionValue {
583    open_paren: copy,
584    leading: owned(Trivia),
585    expr: owned(Expr),
586    trailing: owned(Trivia),
587    close_paren: copy,
588});
589
590// ============================================================================
591// Collection expressions
592// ============================================================================
593
594/// Sequence expression: `[a, b, c]`.
595#[derive(Clone, Debug, PartialEq)]
596pub struct SeqExpr<'a> {
597    /// The span of the entire sequence including brackets.
598    pub span: Span,
599    /// Span of the opening bracket `[`.
600    pub open_bracket: Span,
601    /// Leading trivia after the opening bracket.
602    pub leading: Trivia<'a>,
603    /// The sequence items.
604    pub items: Vec<SeqItem<'a>>,
605    /// Trailing trivia before the closing bracket.
606    pub trailing: Trivia<'a>,
607    /// Span of the closing bracket `]`.
608    pub close_bracket: Span,
609}
610
611impl_into_owned!(SeqExpr {
612    span: copy,
613    open_bracket: copy,
614    leading: owned(Trivia),
615    items: vec(SeqItem),
616    trailing: owned(Trivia),
617    close_bracket: copy,
618});
619
620/// An item in a sequence.
621#[derive(Clone, Debug, PartialEq)]
622pub struct SeqItem<'a> {
623    /// Leading trivia before this item.
624    pub leading: Trivia<'a>,
625    /// The item expression.
626    pub expr: Expr<'a>,
627    /// Trailing trivia after the expression (before comma).
628    pub trailing: Trivia<'a>,
629    /// The trailing comma, if present.
630    pub comma: Option<Span>,
631}
632
633impl_into_owned!(SeqItem {
634    leading: owned(Trivia),
635    expr: owned(Expr),
636    trailing: owned(Trivia),
637    comma: copy,
638});
639
640/// Map expression: `{key: value, ...}`.
641#[derive(Clone, Debug, PartialEq)]
642pub struct MapExpr<'a> {
643    /// The span of the entire map including braces.
644    pub span: Span,
645    /// Span of the opening brace `{`.
646    pub open_brace: Span,
647    /// Leading trivia after the opening brace.
648    pub leading: Trivia<'a>,
649    /// The map entries.
650    pub entries: Vec<MapEntry<'a>>,
651    /// Trailing trivia before the closing brace.
652    pub trailing: Trivia<'a>,
653    /// Span of the closing brace `}`.
654    pub close_brace: Span,
655}
656
657impl_into_owned!(MapExpr {
658    span: copy,
659    open_brace: copy,
660    leading: owned(Trivia),
661    entries: vec(MapEntry),
662    trailing: owned(Trivia),
663    close_brace: copy,
664});
665
666/// An entry in a map: `key: value`.
667#[derive(Clone, Debug, PartialEq)]
668pub struct MapEntry<'a> {
669    /// Leading trivia before the key.
670    pub leading: Trivia<'a>,
671    /// The key expression.
672    pub key: Expr<'a>,
673    /// Trivia between key and colon.
674    pub pre_colon: Trivia<'a>,
675    /// Span of the colon `:`.
676    pub colon: Span,
677    /// Trivia between colon and value.
678    pub post_colon: Trivia<'a>,
679    /// The value expression.
680    pub value: Expr<'a>,
681    /// Trailing trivia after the value (before comma).
682    pub trailing: Trivia<'a>,
683    /// The trailing comma, if present.
684    pub comma: Option<Span>,
685}
686
687impl_into_owned!(MapEntry {
688    leading: owned(Trivia),
689    key: owned(Expr),
690    pre_colon: owned(Trivia),
691    colon: copy,
692    post_colon: owned(Trivia),
693    value: owned(Expr),
694    trailing: owned(Trivia),
695    comma: copy,
696});
697
698/// Tuple expression: `(a, b, c)`.
699///
700/// Note: In RON, a tuple is an unnamed parenthesized list of values.
701/// Named tuples are represented as `StructExpr` with tuple style.
702#[derive(Clone, Debug, PartialEq)]
703pub struct TupleExpr<'a> {
704    /// The span of the entire tuple including parentheses.
705    pub span: Span,
706    /// Span of the opening parenthesis `(`.
707    pub open_paren: Span,
708    /// Leading trivia after the opening parenthesis.
709    pub leading: Trivia<'a>,
710    /// The tuple elements.
711    pub elements: Vec<TupleElement<'a>>,
712    /// Trailing trivia before the closing parenthesis.
713    pub trailing: Trivia<'a>,
714    /// Span of the closing parenthesis `)`.
715    pub close_paren: Span,
716}
717
718impl_into_owned!(TupleExpr {
719    span: copy,
720    open_paren: copy,
721    leading: owned(Trivia),
722    elements: vec(TupleElement),
723    trailing: owned(Trivia),
724    close_paren: copy,
725});
726
727/// Anonymous struct expression: `(field: value, ...)`.
728///
729/// This represents a struct-like value with named fields but no type name.
730#[derive(Clone, Debug, PartialEq)]
731pub struct AnonStructExpr<'a> {
732    /// The span of the entire struct including parentheses.
733    pub span: Span,
734    /// Span of the opening parenthesis `(`.
735    pub open_paren: Span,
736    /// Leading trivia after the opening parenthesis.
737    pub leading: Trivia<'a>,
738    /// The struct fields.
739    pub fields: Vec<StructField<'a>>,
740    /// Trailing trivia before the closing parenthesis.
741    pub trailing: Trivia<'a>,
742    /// Span of the closing parenthesis `)`.
743    pub close_paren: Span,
744}
745
746impl_into_owned!(AnonStructExpr {
747    span: copy,
748    open_paren: copy,
749    leading: owned(Trivia),
750    fields: vec(StructField),
751    trailing: owned(Trivia),
752    close_paren: copy,
753});
754
755/// An element in a tuple.
756#[derive(Clone, Debug, PartialEq)]
757pub struct TupleElement<'a> {
758    /// Leading trivia before this element.
759    pub leading: Trivia<'a>,
760    /// The element expression.
761    pub expr: Expr<'a>,
762    /// Trailing trivia after the expression (before comma).
763    pub trailing: Trivia<'a>,
764    /// The trailing comma, if present.
765    pub comma: Option<Span>,
766}
767
768impl_into_owned!(TupleElement {
769    leading: owned(Trivia),
770    expr: owned(Expr),
771    trailing: owned(Trivia),
772    comma: copy,
773});
774
775// ============================================================================
776// Struct expression
777// ============================================================================
778
779/// Struct expression: `Name(...)`, `Name { ... }`, or `Name`.
780///
781/// This covers:
782/// - Named tuple structs: `Point(1, 2)`
783/// - Named structs with fields: `Config { x: 1, y: 2 }`
784/// - Unit structs: `None` (when not the built-in None)
785/// - Enum variants: `Variant(...)` or `Variant { ... }`
786#[derive(Clone, Debug, PartialEq)]
787pub struct StructExpr<'a> {
788    /// The span of the entire struct expression.
789    pub span: Span,
790    /// The struct/enum name.
791    pub name: Ident<'a>,
792    /// Trivia between name and body (e.g., space in `Point { ... }`).
793    pub pre_body: Trivia<'a>,
794    /// The body of the struct, if any.
795    pub body: Option<StructBody<'a>>,
796}
797
798impl_into_owned!(StructExpr {
799    span: copy,
800    name: owned(Ident),
801    pre_body: owned(Trivia),
802    body: option(StructBody),
803});
804
805/// An identifier (struct name, enum variant, field name).
806#[derive(Clone, Debug, PartialEq, Eq)]
807pub struct Ident<'a> {
808    /// The span of the identifier.
809    pub span: Span,
810    /// The identifier text.
811    pub name: Cow<'a, str>,
812}
813
814impl_into_owned!(Ident {
815    span: copy,
816    name: cow,
817});
818
819/// The body of a struct expression.
820#[derive(Clone, Debug, PartialEq)]
821pub enum StructBody<'a> {
822    /// Tuple-style body: `(a, b, c)`.
823    Tuple(TupleBody<'a>),
824    /// Named fields body: `{ x: 1, y: 2 }`.
825    Fields(FieldsBody<'a>),
826}
827
828impl StructBody<'_> {
829    /// Converts to an owned version with `'static` lifetime.
830    #[must_use]
831    pub fn into_owned(self) -> StructBody<'static> {
832        match self {
833            Self::Tuple(t) => StructBody::Tuple(t.into_owned()),
834            Self::Fields(f) => StructBody::Fields(f.into_owned()),
835        }
836    }
837}
838
839/// Tuple-style struct body: `(a, b, c)`.
840#[derive(Clone, Debug, PartialEq)]
841pub struct TupleBody<'a> {
842    /// Span of the opening parenthesis `(`.
843    pub open_paren: Span,
844    /// Leading trivia after the opening parenthesis.
845    pub leading: Trivia<'a>,
846    /// The tuple elements.
847    pub elements: Vec<TupleElement<'a>>,
848    /// Trailing trivia before the closing parenthesis.
849    pub trailing: Trivia<'a>,
850    /// Span of the closing parenthesis `)`.
851    pub close_paren: Span,
852}
853
854impl_into_owned!(TupleBody {
855    open_paren: copy,
856    leading: owned(Trivia),
857    elements: vec(TupleElement),
858    trailing: owned(Trivia),
859    close_paren: copy,
860});
861
862/// Named fields struct body: `{ x: 1, y: 2 }`.
863#[derive(Clone, Debug, PartialEq)]
864pub struct FieldsBody<'a> {
865    /// Span of the opening brace `{`.
866    pub open_brace: Span,
867    /// Leading trivia after the opening brace.
868    pub leading: Trivia<'a>,
869    /// The struct fields.
870    pub fields: Vec<StructField<'a>>,
871    /// Trailing trivia before the closing brace.
872    pub trailing: Trivia<'a>,
873    /// Span of the closing brace `}`.
874    pub close_brace: Span,
875}
876
877impl_into_owned!(FieldsBody {
878    open_brace: copy,
879    leading: owned(Trivia),
880    fields: vec(StructField),
881    trailing: owned(Trivia),
882    close_brace: copy,
883});
884
885/// A field in a struct: `name: value`.
886#[derive(Clone, Debug, PartialEq)]
887pub struct StructField<'a> {
888    /// Leading trivia before the field name.
889    pub leading: Trivia<'a>,
890    /// The field name.
891    pub name: Ident<'a>,
892    /// Trivia between name and colon.
893    pub pre_colon: Trivia<'a>,
894    /// Span of the colon `:`.
895    pub colon: Span,
896    /// Trivia between colon and value.
897    pub post_colon: Trivia<'a>,
898    /// The field value.
899    pub value: Expr<'a>,
900    /// Trailing trivia after the value (before comma).
901    pub trailing: Trivia<'a>,
902    /// The trailing comma, if present.
903    pub comma: Option<Span>,
904}
905
906impl_into_owned!(StructField {
907    leading: owned(Trivia),
908    name: owned(Ident),
909    pre_colon: owned(Trivia),
910    colon: copy,
911    post_colon: owned(Trivia),
912    value: owned(Expr),
913    trailing: owned(Trivia),
914    comma: copy,
915});