Skip to main content

substrate_data/schema/refs/
ref_id.rs

1//! [`RefId`]: the type of a kind's ids, and its impls for text and numbers.
2
3use std::borrow::Cow;
4use std::fmt;
5
6use crate::model::value::RefKey;
7use crate::schema::{Expected, Schema};
8
9/// The type of a kind's ids: how one is spelled in a reference
10/// (`@user:42`), read back, and stored in every other form (a frame packs
11/// it as itself — a number as a number).
12pub trait RefId: Schema + Clone + PartialEq + fmt::Debug {
13    /// What an id of this type looks like, for messages.
14    const EXPECTED: Expected;
15    /// The id `spelled` is, if it's one of this type.
16    fn parse(spelled: &str) -> Option<Self>;
17    /// As written after `@kind:`.
18    fn spell(&self) -> Cow<'_, str>;
19}
20
21impl RefId for String {
22    const EXPECTED: Expected = Expected::Text;
23    fn parse(spelled: &str) -> Option<Self> {
24        RefKey::is_valid(spelled).then(|| spelled.to_owned())
25    }
26    fn spell(&self) -> Cow<'_, str> {
27        Cow::Borrowed(self)
28    }
29}
30
31macro_rules! number_ids {
32    ($($t:ty => $what:ident),*) => {$(
33        impl RefId for $t {
34            const EXPECTED: Expected = Expected::$what;
35            fn parse(spelled: &str) -> Option<Self> {
36                // Digits only: no sign, no spaces — one spelling per id.
37                let digits = spelled.strip_prefix('-').unwrap_or(spelled);
38                if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
39                    return None;
40                }
41                spelled.parse().ok()
42            }
43            fn spell(&self) -> Cow<'_, str> {
44                Cow::Owned(self.to_string())
45            }
46        }
47    )*};
48}
49number_ids!(u32 => Unsigned, u64 => Unsigned, i64 => Integer);