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