Skip to main content

conjure_cp_core/representation/
id.rs

1use std::fmt::{Display, Formatter};
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use super::registry::get_repr_by_name;
6
7/// The identity of a representation rule.
8///
9/// Identity is the rule's [`NAME`](super::ReprRule::NAME) -- its Rust type name, which is unique
10/// across the registry. A representation's *short* name is not unique: nine representations are
11/// called `packed`, four `components`, four `occurrence`. Wrapping the identity in its own type
12/// keeps a short name from being used as one by accident, which has silently broken rules before.
13///
14/// The short name travels along for display, so rendering a represented name costs no lookup.
15#[derive(Clone, Copy, Debug)]
16pub struct ReprId {
17    name: &'static str,
18    short_name: &'static str,
19}
20
21impl ReprId {
22    /// Builds an id from a rule's name and short name.
23    ///
24    /// Prefer [`ReprRule::id`](super::ReprRule::id) or [`ReprRuleStored::id`](super::ReprRuleStored::id)
25    /// over calling this directly; those cannot disagree with the registry.
26    pub const fn new(name: &'static str, short_name: &'static str) -> Self {
27        ReprId { name, short_name }
28    }
29
30    /// The unique name identifying this representation.
31    pub fn name(self) -> &'static str {
32        self.name
33    }
34
35    /// The Essence-facing name, which several representations may share.
36    pub fn short_name(self) -> &'static str {
37        self.short_name
38    }
39}
40
41impl PartialEq for ReprId {
42    fn eq(&self, other: &Self) -> bool {
43        self.name == other.name
44    }
45}
46
47impl Eq for ReprId {}
48
49impl std::hash::Hash for ReprId {
50    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
51        self.name.hash(state);
52    }
53}
54
55impl PartialOrd for ReprId {
56    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
57        Some(self.cmp(other))
58    }
59}
60
61impl Ord for ReprId {
62    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
63        self.name.cmp(other.name)
64    }
65}
66
67/// Displays the short name, which is what Essence and represented variable names use.
68impl Display for ReprId {
69    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70        write!(f, "{}", self.short_name)
71    }
72}
73
74/// Serialises as the unique name, so stored models survive a short-name change.
75impl Serialize for ReprId {
76    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
77        serializer.serialize_str(self.name)
78    }
79}
80
81impl<'de> Deserialize<'de> for ReprId {
82    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
83        let name = String::deserialize(deserializer)?;
84        get_repr_by_name(&name)
85            .map(|rule| rule.id())
86            .ok_or_else(|| serde::de::Error::custom(format!("unknown representation `{name}`")))
87    }
88}
89
90impl polyquine::Quine for ReprId {
91    fn ctor_tokens(&self) -> proc_macro2::TokenStream {
92        let name = self.name;
93        quote::quote! {
94            conjure_cp::representation::get_repr_by_name(#name)
95                .expect("representation should be registered")
96                .id()
97        }
98    }
99}