Skip to main content

mf2_model/
message.rs

1//! Messages, declarations and variants (`spec/data-model/README.md`,
2//! "Message Model").
3
4use alloc::borrow::Cow;
5use alloc::vec::Vec;
6
7use crate::expression::{Expression, Literal, VariableExpression, VariableRef};
8use crate::pattern::Pattern;
9
10/// A message: a single pattern, or a selection among variants.
11#[derive(Clone, PartialEq, Eq, Hash, Debug)]
12// Future versions of MF2 may define new structures (the specification's
13// stability policy); a new one is a new variant, which a 1.x minor may add.
14#[non_exhaustive]
15pub enum Message<'a> {
16    /// No selectors: one pattern.
17    Pattern(PatternMessage<'a>),
18    /// `.match` with selectors and variants.
19    Select(SelectMessage<'a>),
20}
21
22impl<'a> Message<'a> {
23    /// The declarations of either kind of message.
24    pub fn declarations(&self) -> &[Declaration<'a>] {
25        match self {
26            Message::Pattern(m) => &m.declarations,
27            Message::Select(m) => &m.declarations,
28        }
29    }
30
31    /// The same message with every string owned.
32    pub fn into_owned(self) -> Message<'static> {
33        match self {
34            Message::Pattern(m) => Message::Pattern(m.into_owned()),
35            Message::Select(m) => Message::Select(m.into_owned()),
36        }
37    }
38}
39
40/// A message without selectors: declarations and one pattern.
41#[derive(Clone, PartialEq, Eq, Hash, Debug)]
42pub struct PatternMessage<'a> {
43    /// `.input` and `.local` declarations, in source order.
44    pub declarations: Vec<Declaration<'a>>,
45    /// The pattern.
46    pub pattern: Pattern<'a>,
47}
48
49impl PatternMessage<'_> {
50    /// The same message with every string owned.
51    pub fn into_owned(self) -> PatternMessage<'static> {
52        PatternMessage {
53            declarations: self
54                .declarations
55                .into_iter()
56                .map(Declaration::into_owned)
57                .collect(),
58            pattern: self.pattern.into_owned(),
59        }
60    }
61}
62
63/// A message with a matcher: declarations, selectors and variants.
64#[derive(Clone, PartialEq, Eq, Hash, Debug)]
65pub struct SelectMessage<'a> {
66    /// `.input` and `.local` declarations, in source order.
67    pub declarations: Vec<Declaration<'a>>,
68    /// The selectors, in source order.
69    pub selectors: Vec<VariableRef<'a>>,
70    /// The variants, in source order.
71    pub variants: Vec<Variant<'a>>,
72}
73
74impl SelectMessage<'_> {
75    /// The same message with every string owned.
76    pub fn into_owned(self) -> SelectMessage<'static> {
77        SelectMessage {
78            declarations: self
79                .declarations
80                .into_iter()
81                .map(Declaration::into_owned)
82                .collect(),
83            selectors: self
84                .selectors
85                .into_iter()
86                .map(VariableRef::into_owned)
87                .collect(),
88            variants: self.variants.into_iter().map(Variant::into_owned).collect(),
89        }
90    }
91}
92
93/// A declaration.
94#[derive(Clone, PartialEq, Eq, Hash, Debug)]
95// Future versions of MF2 may define new structures (the specification's
96// stability policy); a new one is a new variant, which a 1.x minor may add.
97#[non_exhaustive]
98pub enum Declaration<'a> {
99    /// `.input {$name …}`.
100    Input(InputDeclaration<'a>),
101    /// `.local $name = {…}`.
102    Local(LocalDeclaration<'a>),
103}
104
105impl Declaration<'_> {
106    /// The variable the declaration binds.
107    pub fn name(&self) -> &str {
108        match self {
109            Declaration::Input(d) => &d.name,
110            Declaration::Local(d) => &d.name,
111        }
112    }
113
114    /// The same declaration with every string owned.
115    pub fn into_owned(self) -> Declaration<'static> {
116        match self {
117            Declaration::Input(d) => Declaration::Input(d.into_owned()),
118            Declaration::Local(d) => Declaration::Local(d.into_owned()),
119        }
120    }
121}
122
123/// `.input {$name …}`: binds an external variable, optionally through a
124/// function.
125#[derive(Clone, PartialEq, Eq, Hash, Debug)]
126pub struct InputDeclaration<'a> {
127    /// The bound variable; equals `value.arg.name`.
128    pub name: Cow<'a, str>,
129    /// The variable expression.
130    pub value: VariableExpression<'a>,
131}
132
133impl InputDeclaration<'_> {
134    /// The same declaration with every string owned.
135    pub fn into_owned(self) -> InputDeclaration<'static> {
136        InputDeclaration {
137            name: Cow::Owned(self.name.into_owned()),
138            value: self.value.into_owned(),
139        }
140    }
141}
142
143/// `.local $name = {…}`: binds a local variable to an expression.
144#[derive(Clone, PartialEq, Eq, Hash, Debug)]
145pub struct LocalDeclaration<'a> {
146    /// The bound variable.
147    pub name: Cow<'a, str>,
148    /// The expression.
149    pub value: Expression<'a>,
150}
151
152impl LocalDeclaration<'_> {
153    /// The same declaration with every string owned.
154    pub fn into_owned(self) -> LocalDeclaration<'static> {
155        LocalDeclaration {
156            name: Cow::Owned(self.name.into_owned()),
157            value: self.value.into_owned(),
158        }
159    }
160}
161
162/// A variant: one key per selector, and a pattern.
163#[derive(Clone, PartialEq, Eq, Hash, Debug)]
164pub struct Variant<'a> {
165    /// The keys, in source order.
166    pub keys: Vec<Key<'a>>,
167    /// The pattern.
168    pub value: Pattern<'a>,
169}
170
171impl Variant<'_> {
172    /// The same variant with every string owned.
173    pub fn into_owned(self) -> Variant<'static> {
174        Variant {
175            keys: self.keys.into_iter().map(Key::into_owned).collect(),
176            value: self.value.into_owned(),
177        }
178    }
179}
180
181/// A variant key.
182#[derive(Clone, PartialEq, Eq, Hash, Debug)]
183// Future versions of MF2 may define new structures (the specification's
184// stability policy); a new one is a new variant, which a 1.x minor may add.
185#[non_exhaustive]
186pub enum Key<'a> {
187    /// A literal key.
188    Literal(Literal<'a>),
189    /// The catch-all key `*`.
190    CatchAll(CatchAllKey<'a>),
191}
192
193impl Key<'_> {
194    /// The same key with every string owned.
195    pub fn into_owned(self) -> Key<'static> {
196        match self {
197            Key::Literal(l) => Key::Literal(l.into_owned()),
198            Key::CatchAll(c) => Key::CatchAll(c.into_owned()),
199        }
200    }
201}
202
203/// The catch-all key. Its `value` lets other formats keep an identifier; it
204/// is always `None` from MF2 syntax, where the key is written `*`.
205#[derive(Clone, Default, PartialEq, Eq, Hash, Debug)]
206pub struct CatchAllKey<'a> {
207    /// An identifier kept from another format, if any.
208    pub value: Option<Cow<'a, str>>,
209}
210
211impl CatchAllKey<'_> {
212    /// The same key with every string owned.
213    pub fn into_owned(self) -> CatchAllKey<'static> {
214        CatchAllKey {
215            value: self.value.map(|v| Cow::Owned(v.into_owned())),
216        }
217    }
218}