Skip to main content

jacquard_common/
types.rs

1use serde::{Deserialize, Serialize};
2
3// Re-export Lazy from crate root for submodule use via `super::Lazy`
4pub use crate::Lazy;
5
6/// AT Protocol URI (at://) types and validation
7pub mod aturi;
8/// Blob references for binary data
9pub mod blob;
10/// Content Identifier (CID) types for IPLD
11pub mod cid;
12/// Repository collection trait for records
13pub mod collection;
14pub mod crypto;
15/// AT Protocol datetime string type
16pub mod datetime;
17/// Decentralized Identifier (DID) types and validation
18pub mod did;
19/// DID Document types and helpers
20pub mod did_doc;
21/// DID service audience types and validation.
22pub mod did_service;
23/// AT Protocol handle types and validation
24pub mod handle;
25/// AT Protocol identifier types (handle or DID)
26pub mod ident;
27pub mod integer;
28/// Language tag types per BCP 47
29pub mod language;
30/// Namespaced Identifier (NSID) types and validation
31pub mod nsid;
32/// Record key types and validation
33pub mod recordkey;
34/// Scope action and resource enums for AT Protocol OAuth
35pub mod scope_primitives;
36/// String types with format validation
37pub mod string;
38/// Timestamp Identifier (TID) types and generation
39pub mod tid;
40/// URI types with scheme validation
41pub mod uri;
42/// Generic data value types for lexicon data model
43pub mod value;
44
45/// Trait for a constant string literal type
46pub trait Literal: Clone + Copy + PartialEq + Eq + Send + Sync + 'static {
47    /// The string literal
48    const LITERAL: &'static str;
49}
50
51/// top-level domains which are not allowed in at:// handles or dids
52pub const DISALLOWED_TLDS: &[&str] = &[
53    ".local",
54    ".arpa",
55    ".invalid", // NOTE: if someone has a screwed up handle, this is what's returned
56    ".localhost",
57    ".internal",
58    ".example",
59    ".alt",
60    // policy could concievably change on ".onion" some day
61    ".onion",
62    // NOTE: .test is allowed in testing and devopment. In practical terms
63    // "should" "never" actually resolve and get registered in production
64];
65
66/// checks if a string ends with anything from the provided list of strings.
67pub fn ends_with(string: impl AsRef<str>, list: &[&str]) -> bool {
68    let string = string.as_ref();
69    for item in list {
70        if string.ends_with(item) {
71            return true;
72        }
73    }
74    false
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
78#[serde(rename_all = "kebab-case")]
79/// Valid types in the AT protocol [data model](https://atproto.com/specs/data-model). Type marker only, used in concert with `[Data<'_>]`.
80pub enum DataModelType {
81    /// Null type. IPLD type `null`, JSON type `Null`, CBOR Special Value (major 7)
82    Null,
83    /// Boolean type. IPLD type `boolean`, JSON type Boolean, CBOR Special Value (major 7)
84    Boolean,
85    /// Integer type. IPLD type `integer`, JSON type Number, CBOR Special Value (major 7)
86    Integer,
87    /// Byte type. IPLD type `bytes`, in JSON a `{ "$bytes": bytes }` Object, CBOR Byte String (major 2)
88    Bytes,
89    /// CID (content identifier) link. IPLD type `link`, in JSON a `{ "$link": cid }` Object, CBOR CID (tag 42)
90    CidLink,
91    /// Blob type. No special IPLD type. in JSON a `{ "$type": "blob" }` Object. in CBOR a `{ "$type": "blob" }` Map.
92    Blob,
93    /// Array type. IPLD type `list`. JSON type `Array`, CBOR type Array (major 4)
94    Array,
95    /// Object type. IPLD type `map`. JSON type `Object`, CBOR type Map (major 5). keys are always SmolStr.
96    Object,
97    #[serde(untagged)]
98    /// String type (lots of variants). JSON String, CBOR UTF-8 String (major 3)
99    String(LexiconStringType),
100}
101
102impl core::fmt::Display for DataModelType {
103    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
104        match self {
105            DataModelType::Null => write!(f, "null"),
106            DataModelType::Boolean => write!(f, "boolean"),
107            DataModelType::Integer => write!(f, "integer"),
108            DataModelType::Bytes => write!(f, "bytes"),
109            DataModelType::CidLink => write!(f, "cid-link"),
110            DataModelType::Blob => write!(f, "blob"),
111            DataModelType::Array => write!(f, "array"),
112            DataModelType::Object => write!(f, "object"),
113            DataModelType::String(s) => write!(f, "{}", s),
114        }
115    }
116}
117
118/// Lexicon string format types for typed strings in the AT Protocol data model
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
120#[serde(rename_all = "kebab-case")]
121pub enum LexiconStringType {
122    /// ISO 8601 datetime string
123    Datetime,
124    /// AT Protocol URI (at://)
125    AtUri,
126    /// Decentralized Identifier
127    Did,
128    /// AT Protocol handle
129    Handle,
130    /// Handle or DID
131    AtIdentifier,
132    /// Namespaced Identifier
133    Nsid,
134    /// Content Identifier
135    Cid,
136    /// BCP 47 language tag
137    Language,
138    /// Timestamp Identifier
139    Tid,
140    /// Record key
141    RecordKey,
142    /// URI with type constraint
143    Uri(UriType),
144    /// Plain string
145    #[serde(untagged)]
146    String,
147}
148
149impl core::fmt::Display for LexiconStringType {
150    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
151        match self {
152            LexiconStringType::Datetime => write!(f, "datetime"),
153            LexiconStringType::AtUri => write!(f, "at-uri"),
154            LexiconStringType::Did => write!(f, "did"),
155            LexiconStringType::Handle => write!(f, "handle"),
156            LexiconStringType::AtIdentifier => write!(f, "at-identifier"),
157            LexiconStringType::Nsid => write!(f, "nsid"),
158            LexiconStringType::Cid => write!(f, "cid"),
159            LexiconStringType::Language => write!(f, "language"),
160            LexiconStringType::Tid => write!(f, "tid"),
161            LexiconStringType::RecordKey => write!(f, "record-key"),
162            LexiconStringType::Uri(u) => write!(f, "uri({})", u),
163            LexiconStringType::String => write!(f, "string"),
164        }
165    }
166}
167
168/// URI scheme types for lexicon URI format constraints
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
170#[serde(tag = "type")]
171pub enum UriType {
172    /// DID URI (did:)
173    Did,
174    /// AT Protocol URI (at://)
175    At,
176    /// HTTPS URI
177    Https,
178    /// WebSocket Secure URI
179    Wss,
180    /// CID URI
181    Cid,
182    /// DNS name
183    Dns,
184    /// Any valid URI
185    Any,
186}
187
188impl core::fmt::Display for UriType {
189    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
190        match self {
191            UriType::Did => write!(f, "did"),
192            UriType::At => write!(f, "at"),
193            UriType::Https => write!(f, "https"),
194            UriType::Wss => write!(f, "wss"),
195            UriType::Cid => write!(f, "cid"),
196            UriType::Dns => write!(f, "dns"),
197            UriType::Any => write!(f, "any"),
198        }
199    }
200}