1
use std::fmt::{Display, Formatter};
2

            
3
use serde::{Deserialize, Deserializer, Serialize, Serializer};
4

            
5
use 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)]
16
pub struct ReprId {
17
    name: &'static str,
18
    short_name: &'static str,
19
}
20

            
21
impl 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
766913616
    pub const fn new(name: &'static str, short_name: &'static str) -> Self {
27
766913616
        ReprId { name, short_name }
28
766913616
    }
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

            
41
impl PartialEq for ReprId {
42
3734722195
    fn eq(&self, other: &Self) -> bool {
43
3734722195
        self.name == other.name
44
3734722195
    }
45
}
46

            
47
impl Eq for ReprId {}
48

            
49
impl std::hash::Hash for ReprId {
50
5366800531
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
51
5366800531
        self.name.hash(state);
52
5366800531
    }
53
}
54

            
55
impl PartialOrd for ReprId {
56
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
57
        Some(self.cmp(other))
58
    }
59
}
60

            
61
impl Ord for ReprId {
62
14975769936
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
63
14975769936
        self.name.cmp(other.name)
64
14975769936
    }
65
}
66

            
67
/// Displays the short name, which is what Essence and represented variable names use.
68
impl Display for ReprId {
69
206323373
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70
206323373
        write!(f, "{}", self.short_name)
71
206323373
    }
72
}
73

            
74
/// Serialises as the unique name, so stored models survive a short-name change.
75
impl Serialize for ReprId {
76
6146553
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
77
6146553
        serializer.serialize_str(self.name)
78
6146553
    }
79
}
80

            
81
impl<'de> Deserialize<'de> for ReprId {
82
4918189
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
83
4918189
        let name = String::deserialize(deserializer)?;
84
4918189
        get_repr_by_name(&name)
85
4918189
            .map(|rule| rule.id())
86
            .ok_or_else(|| serde::de::Error::custom(format!("unknown representation `{name}`")))
87
4918189
    }
88
}
89

            
90
impl 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
}