Skip to main content

substrate_data/schema/refs/
kind.rs

1//! [`Kind`] and [`Kinds`]: what a reference names, declared with `kind!`.
2
3use super::RefId;
4use crate::model::value::KindName;
5
6/// A kind of thing a reference names: `user`, `doc`, `file`, ... — a
7/// format declares its own with [`kind!`](crate::kind), each with the type
8/// of its ids.
9pub trait Kind {
10    /// As written: lower case letters, digits and `_` (`kind!` checks it
11    /// when it compiles).
12    const NAME: &'static str;
13    /// Its ids.
14    type Id: RefId;
15
16    /// [`Kind::NAME`] as a kind.
17    #[must_use]
18    fn kind_name() -> KindName {
19        KindName::declared(Self::NAME)
20    }
21}
22
23/// One kind or several (`(File, Doc)`, sharing an id type): what a
24/// reference field takes.
25pub trait Kinds {
26    /// Every kind's name, the first the one written.
27    const NAMES: &'static [&'static str];
28    /// Their ids' type, the same for every kind.
29    type Id: RefId;
30
31    /// The first of them: what a reference this reads is written as.
32    #[must_use]
33    fn first() -> KindName {
34        KindName::declared(Self::NAMES.first().copied().unwrap_or_default())
35    }
36}
37
38impl<K: Kind> Kinds for K {
39    const NAMES: &'static [&'static str] = &[K::NAME];
40    type Id = K::Id;
41}
42
43impl<A: Kind, B: Kind<Id = A::Id>> Kinds for (A, B) {
44    const NAMES: &'static [&'static str] = &[A::NAME, B::NAME];
45    type Id = A::Id;
46}
47
48impl<A: Kind, B: Kind<Id = A::Id>, C: Kind<Id = A::Id>> Kinds for (A, B, C) {
49    const NAMES: &'static [&'static str] = &[A::NAME, B::NAME, C::NAME];
50    type Id = A::Id;
51}
52
53/// Declares kinds, each with its id type (`String` when none is said):
54/// `substrate_data::kind!(User = "user": u64, Doc = "doc");`.
55#[macro_export]
56macro_rules! kind {
57    ($($name:ident = $kind:literal $(: $id:ty)?),* $(,)?) => {$(
58        #[doc = concat!("The `", $kind, "` kind of reference.")]
59        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
60        pub struct $name;
61        impl $crate::Kind for $name {
62            const NAME: &'static str = {
63                assert!(
64                    $crate::KindName::is_valid($kind),
65                    "a kind is lower case letters, digits and `_`, starting with a letter"
66                );
67                $kind
68            };
69            type Id = $crate::__id_or_string!($($id)?);
70        }
71    )*};
72}
73
74#[doc(hidden)]
75#[macro_export]
76macro_rules! __id_or_string {
77    () => {
78        ::std::string::String
79    };
80    ($id:ty) => {
81        $id
82    };
83}