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});