Skip to main content

grc_20/
genesis.rs

1//! Genesis Space well-known IDs.
2//!
3//! The Genesis Space provides well-known IDs for core properties, types,
4//! and relation types (spec Section 7).
5
6use crate::model::{derived_uuid, Id};
7
8// =============================================================================
9// ID DERIVATION
10// =============================================================================
11
12/// Derives a genesis ID from a name.
13///
14/// ```text
15/// id = derived_uuid("grc20:genesis:" + name)
16/// ```
17pub fn genesis_id(name: &str) -> Id {
18    let input = format!("grc20:genesis:{}", name);
19    derived_uuid(input.as_bytes())
20}
21
22/// Derives a language ID from an ISO language code.
23///
24/// ```text
25/// id = derived_uuid("grc20:genesis:language:" + code)
26/// ```
27pub fn language_id(code: &str) -> Id {
28    let input = format!("grc20:genesis:language:{}", code);
29    derived_uuid(input.as_bytes())
30}
31
32// =============================================================================
33// CORE PROPERTIES (Section 7.1)
34// =============================================================================
35
36/// Well-known property IDs from the Genesis Space.
37pub mod properties {
38    use super::*;
39
40    lazy_static::lazy_static! {
41        /// Name property - primary label (TEXT)
42        pub static ref NAME: Id = genesis_id("Name");
43
44        /// Description property - summary text (TEXT)
45        pub static ref DESCRIPTION: Id = genesis_id("Description");
46
47        /// Avatar property - image URL (TEXT)
48        pub static ref AVATAR: Id = genesis_id("Avatar");
49
50        /// URL property - external link (TEXT)
51        pub static ref URL: Id = genesis_id("URL");
52
53        /// Created property - creation time (TIMESTAMP)
54        pub static ref CREATED: Id = genesis_id("Created");
55
56        /// Modified property - last modification (TIMESTAMP)
57        pub static ref MODIFIED: Id = genesis_id("Modified");
58    }
59
60    /// Returns the Name property ID.
61    pub fn name() -> Id {
62        *NAME
63    }
64
65    /// Returns the Description property ID.
66    pub fn description() -> Id {
67        *DESCRIPTION
68    }
69
70    /// Returns the Avatar property ID.
71    pub fn avatar() -> Id {
72        *AVATAR
73    }
74
75    /// Returns the URL property ID.
76    pub fn url() -> Id {
77        *URL
78    }
79
80    /// Returns the Created property ID.
81    pub fn created() -> Id {
82        *CREATED
83    }
84
85    /// Returns the Modified property ID.
86    pub fn modified() -> Id {
87        *MODIFIED
88    }
89}
90
91// =============================================================================
92// CORE TYPES (Section 7.2)
93// =============================================================================
94
95/// Well-known type entity IDs from the Genesis Space.
96pub mod types {
97    use super::*;
98
99    lazy_static::lazy_static! {
100        /// Person type - human individual
101        pub static ref PERSON: Id = genesis_id("Person");
102
103        /// Organization type - company, DAO, institution
104        pub static ref ORGANIZATION: Id = genesis_id("Organization");
105
106        /// Place type - geographic location
107        pub static ref PLACE: Id = genesis_id("Place");
108
109        /// Topic type - subject or concept
110        pub static ref TOPIC: Id = genesis_id("Topic");
111    }
112
113    /// Returns the Person type ID.
114    pub fn person() -> Id {
115        *PERSON
116    }
117
118    /// Returns the Organization type ID.
119    pub fn organization() -> Id {
120        *ORGANIZATION
121    }
122
123    /// Returns the Place type ID.
124    pub fn place() -> Id {
125        *PLACE
126    }
127
128    /// Returns the Topic type ID.
129    pub fn topic() -> Id {
130        *TOPIC
131    }
132}
133
134// =============================================================================
135// CORE RELATION TYPES (Section 7.3)
136// =============================================================================
137
138/// Well-known relation type IDs from the Genesis Space.
139pub mod relation_types {
140    use super::*;
141
142    lazy_static::lazy_static! {
143        /// Types relation - type membership
144        pub static ref TYPES: Id = genesis_id("Types");
145
146        /// PartOf relation - composition/containment
147        pub static ref PART_OF: Id = genesis_id("PartOf");
148
149        /// RelatedTo relation - generic association
150        pub static ref RELATED_TO: Id = genesis_id("RelatedTo");
151    }
152
153    /// Returns the Types relation type ID.
154    pub fn types() -> Id {
155        *TYPES
156    }
157
158    /// Returns the PartOf relation type ID.
159    pub fn part_of() -> Id {
160        *PART_OF
161    }
162
163    /// Returns the RelatedTo relation type ID.
164    pub fn related_to() -> Id {
165        *RELATED_TO
166    }
167}
168
169// =============================================================================
170// LANGUAGES (Section 7.4)
171// =============================================================================
172
173/// Well-known language IDs from the Genesis Space.
174pub mod languages {
175    use super::*;
176
177    lazy_static::lazy_static! {
178        pub static ref ENGLISH: Id = language_id("en");
179        pub static ref SPANISH: Id = language_id("es");
180        pub static ref FRENCH: Id = language_id("fr");
181        pub static ref GERMAN: Id = language_id("de");
182        pub static ref CHINESE: Id = language_id("zh");
183        pub static ref JAPANESE: Id = language_id("ja");
184        pub static ref KOREAN: Id = language_id("ko");
185        pub static ref PORTUGUESE: Id = language_id("pt");
186        pub static ref ITALIAN: Id = language_id("it");
187        pub static ref RUSSIAN: Id = language_id("ru");
188        pub static ref ARABIC: Id = language_id("ar");
189        pub static ref HINDI: Id = language_id("hi");
190    }
191
192    /// Returns the language ID for the given ISO code.
193    ///
194    /// This dynamically derives the ID - for frequently used languages,
195    /// use the static constants instead.
196    pub fn from_code(code: &str) -> Id {
197        language_id(code)
198    }
199
200    pub fn english() -> Id {
201        *ENGLISH
202    }
203
204    pub fn spanish() -> Id {
205        *SPANISH
206    }
207
208    pub fn french() -> Id {
209        *FRENCH
210    }
211
212    pub fn german() -> Id {
213        *GERMAN
214    }
215
216    pub fn chinese() -> Id {
217        *CHINESE
218    }
219
220    pub fn japanese() -> Id {
221        *JAPANESE
222    }
223
224    pub fn korean() -> Id {
225        *KOREAN
226    }
227
228    pub fn portuguese() -> Id {
229        *PORTUGUESE
230    }
231
232    pub fn italian() -> Id {
233        *ITALIAN
234    }
235
236    pub fn russian() -> Id {
237        *RUSSIAN
238    }
239
240    pub fn arabic() -> Id {
241        *ARABIC
242    }
243
244    pub fn hindi() -> Id {
245        *HINDI
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use crate::model::format_id;
253
254    #[test]
255    fn test_genesis_id_deterministic() {
256        let id1 = genesis_id("Name");
257        let id2 = genesis_id("Name");
258        assert_eq!(id1, id2);
259    }
260
261    #[test]
262    fn test_genesis_id_unique() {
263        let name_id = genesis_id("Name");
264        let desc_id = genesis_id("Description");
265        assert_ne!(name_id, desc_id);
266    }
267
268    #[test]
269    fn test_language_id_deterministic() {
270        let en1 = language_id("en");
271        let en2 = language_id("en");
272        assert_eq!(en1, en2);
273    }
274
275    #[test]
276    fn test_genesis_id_format() {
277        // Genesis IDs should be valid UUIDv8
278        let id = genesis_id("Name");
279        // Version should be 8 (0x80 in high nibble of byte 6)
280        assert_eq!(id[6] & 0xF0, 0x80);
281        // Variant should be RFC 4122 (0b10 in high 2 bits of byte 8)
282        assert_eq!(id[8] & 0xC0, 0x80);
283    }
284
285    #[test]
286    fn test_static_properties() {
287        // Verify static properties match dynamic derivation
288        assert_eq!(properties::name(), genesis_id("Name"));
289        assert_eq!(properties::description(), genesis_id("Description"));
290        assert_eq!(properties::avatar(), genesis_id("Avatar"));
291        assert_eq!(properties::url(), genesis_id("URL"));
292        assert_eq!(properties::created(), genesis_id("Created"));
293        assert_eq!(properties::modified(), genesis_id("Modified"));
294    }
295
296    #[test]
297    fn test_static_types() {
298        assert_eq!(types::person(), genesis_id("Person"));
299        assert_eq!(types::organization(), genesis_id("Organization"));
300        assert_eq!(types::place(), genesis_id("Place"));
301        assert_eq!(types::topic(), genesis_id("Topic"));
302    }
303
304    #[test]
305    fn test_static_relation_types() {
306        assert_eq!(relation_types::types(), genesis_id("Types"));
307        assert_eq!(relation_types::part_of(), genesis_id("PartOf"));
308        assert_eq!(relation_types::related_to(), genesis_id("RelatedTo"));
309    }
310
311    #[test]
312    fn test_static_languages() {
313        assert_eq!(languages::english(), language_id("en"));
314        assert_eq!(languages::spanish(), language_id("es"));
315        assert_eq!(languages::from_code("en"), languages::english());
316    }
317
318    #[test]
319    fn test_print_genesis_ids() {
320        // This test prints genesis IDs for documentation
321        println!("=== Core Properties ===");
322        println!("Name: {}", format_id(&properties::name()));
323        println!("Description: {}", format_id(&properties::description()));
324        println!("Avatar: {}", format_id(&properties::avatar()));
325        println!("URL: {}", format_id(&properties::url()));
326        println!("Created: {}", format_id(&properties::created()));
327        println!("Modified: {}", format_id(&properties::modified()));
328
329        println!("\n=== Core Types ===");
330        println!("Person: {}", format_id(&types::person()));
331        println!("Organization: {}", format_id(&types::organization()));
332        println!("Place: {}", format_id(&types::place()));
333        println!("Topic: {}", format_id(&types::topic()));
334
335        println!("\n=== Core Relation Types ===");
336        println!("Types: {}", format_id(&relation_types::types()));
337        println!("PartOf: {}", format_id(&relation_types::part_of()));
338        println!("RelatedTo: {}", format_id(&relation_types::related_to()));
339
340        println!("\n=== Languages ===");
341        println!("English (en): {}", format_id(&languages::english()));
342        println!("Spanish (es): {}", format_id(&languages::spanish()));
343        println!("French (fr): {}", format_id(&languages::french()));
344    }
345}