A better Rust ATProto crate
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[jacquard-common] add hand-written atproto XRPC types for codegen bootstrapping

Create xrpc/atproto.rs module with minimal XRPC endpoint types for:
- com.atproto.repo.listRecords
- com.atproto.repo.getRecord
- com.atproto.identity.resolveHandle
- com.atproto.identity.resolveDid

These types are vendored in jacquard-common to break circular dependencies
between jacquard-lexgen/jacquard-identity and jacquard-api. Implements
XrpcRequest/XrpcResp traits and manual IntoStatic impls (cannot use
jacquard_derive::IntoStatic due to lack of jacquard-derive dependency).

Includes 10 unit tests verifying serialization, deserialization, and
IntoStatic trait implementation for all types.

+136 -14
+136 -14
crates/jacquard-common/src/xrpc/atproto.rs
··· 5 5 //! implementations sufficient for bootstrap code generation without builders or 6 6 //! validation helpers. 7 7 8 - use crate::{CowStr, IntoStatic}; 8 + use alloc::vec::Vec; 9 + use crate::CowStr; 10 + use crate::IntoStatic; 9 11 use crate::types::string::{AtUri, Cid, Did, Handle, Nsid}; 10 12 use crate::types::ident::AtIdentifier; 11 13 use crate::types::value::Data; ··· 26 28 Clone, 27 29 PartialEq, 28 30 Eq, 29 - jacquard_derive::IntoStatic, 30 31 )] 31 32 #[serde(rename_all = "camelCase")] 32 33 pub struct ListRecords<'a> { ··· 41 42 pub repo: AtIdentifier<'a>, 42 43 #[serde(skip_serializing_if = "Option::is_none")] 43 44 pub reverse: Option<bool>, 45 + } 46 + 47 + impl IntoStatic for ListRecords<'_> { 48 + type Output = ListRecords<'static>; 49 + 50 + fn into_static(self) -> Self::Output { 51 + ListRecords { 52 + collection: self.collection.into_static(), 53 + cursor: self.cursor.into_static(), 54 + limit: self.limit, 55 + repo: self.repo.into_static(), 56 + reverse: self.reverse, 57 + } 58 + } 44 59 } 45 60 46 61 /// Output for com.atproto.repo.listRecords. ··· 51 66 Clone, 52 67 PartialEq, 53 68 Eq, 54 - jacquard_derive::IntoStatic, 55 69 )] 56 70 #[serde(rename_all = "camelCase")] 57 71 pub struct ListRecordsOutput<'a> { ··· 62 76 pub records: Vec<ListRecordsRecord<'a>>, 63 77 } 64 78 79 + impl IntoStatic for ListRecordsOutput<'_> { 80 + type Output = ListRecordsOutput<'static>; 81 + 82 + fn into_static(self) -> Self::Output { 83 + ListRecordsOutput { 84 + cursor: self.cursor.into_static(), 85 + records: self.records.into_static(), 86 + } 87 + } 88 + } 89 + 65 90 /// A single record in a list response. 66 91 #[derive( 67 92 Serialize, ··· 70 95 Clone, 71 96 PartialEq, 72 97 Eq, 73 - jacquard_derive::IntoStatic, 74 98 )] 75 99 #[serde(rename_all = "camelCase")] 76 100 pub struct ListRecordsRecord<'a> { ··· 83 107 pub value: Data<'a>, 84 108 } 85 109 110 + impl IntoStatic for ListRecordsRecord<'_> { 111 + type Output = ListRecordsRecord<'static>; 112 + 113 + fn into_static(self) -> Self::Output { 114 + ListRecordsRecord { 115 + cid: self.cid.into_static(), 116 + uri: self.uri.into_static(), 117 + value: self.value.into_static(), 118 + } 119 + } 120 + } 121 + 86 122 /// Response marker for com.atproto.repo.listRecords. 87 123 pub struct ListRecordsResponse; 88 124 ··· 111 147 Clone, 112 148 PartialEq, 113 149 Eq, 114 - jacquard_derive::IntoStatic, 115 150 )] 116 151 #[serde(rename_all = "camelCase")] 117 152 pub struct GetRecord<'a> { ··· 126 161 pub rkey: CowStr<'a>, 127 162 } 128 163 164 + impl IntoStatic for GetRecord<'_> { 165 + type Output = GetRecord<'static>; 166 + 167 + fn into_static(self) -> Self::Output { 168 + GetRecord { 169 + cid: self.cid.into_static(), 170 + collection: self.collection.into_static(), 171 + repo: self.repo.into_static(), 172 + rkey: self.rkey.into_static(), 173 + } 174 + } 175 + } 176 + 129 177 /// Output for com.atproto.repo.getRecord. 130 178 #[derive( 131 179 Serialize, ··· 134 182 Clone, 135 183 PartialEq, 136 184 Eq, 137 - jacquard_derive::IntoStatic, 138 185 )] 139 186 #[serde(rename_all = "camelCase")] 140 187 pub struct GetRecordOutput<'a> { ··· 147 194 pub value: Data<'a>, 148 195 } 149 196 197 + impl IntoStatic for GetRecordOutput<'_> { 198 + type Output = GetRecordOutput<'static>; 199 + 200 + fn into_static(self) -> Self::Output { 201 + GetRecordOutput { 202 + cid: self.cid.into_static(), 203 + uri: self.uri.into_static(), 204 + value: self.value.into_static(), 205 + } 206 + } 207 + } 208 + 150 209 /// Error type for com.atproto.repo.getRecord. 151 210 #[derive( 152 211 Serialize, ··· 155 214 Clone, 156 215 PartialEq, 157 216 Eq, 158 - jacquard_derive::IntoStatic, 159 217 )] 160 218 #[serde(tag = "error", content = "message")] 161 219 #[serde(bound(deserialize = "'de: 'a"))] ··· 180 238 181 239 impl Error for GetRecordError<'_> {} 182 240 241 + impl IntoStatic for GetRecordError<'_> { 242 + type Output = GetRecordError<'static>; 243 + 244 + fn into_static(self) -> Self::Output { 245 + match self { 246 + Self::RecordNotFound(msg) => GetRecordError::RecordNotFound(msg.into_static()), 247 + } 248 + } 249 + } 250 + 183 251 /// Response marker for com.atproto.repo.getRecord. 184 252 pub struct GetRecordResponse; 185 253 ··· 208 276 Clone, 209 277 PartialEq, 210 278 Eq, 211 - jacquard_derive::IntoStatic, 212 279 )] 213 280 #[serde(rename_all = "camelCase")] 214 281 pub struct ResolveHandle<'a> { ··· 216 283 pub handle: Handle<'a>, 217 284 } 218 285 286 + impl IntoStatic for ResolveHandle<'_> { 287 + type Output = ResolveHandle<'static>; 288 + 289 + fn into_static(self) -> Self::Output { 290 + ResolveHandle { 291 + handle: self.handle.into_static(), 292 + } 293 + } 294 + } 295 + 219 296 /// Output for com.atproto.identity.resolveHandle. 220 297 #[derive( 221 298 Serialize, ··· 224 301 Clone, 225 302 PartialEq, 226 303 Eq, 227 - jacquard_derive::IntoStatic, 228 304 )] 229 305 #[serde(rename_all = "camelCase")] 230 306 pub struct ResolveHandleOutput<'a> { ··· 232 308 pub did: Did<'a>, 233 309 } 234 310 311 + impl IntoStatic for ResolveHandleOutput<'_> { 312 + type Output = ResolveHandleOutput<'static>; 313 + 314 + fn into_static(self) -> Self::Output { 315 + ResolveHandleOutput { 316 + did: self.did.into_static(), 317 + } 318 + } 319 + } 320 + 235 321 /// Error type for com.atproto.identity.resolveHandle. 236 322 #[derive( 237 323 Serialize, ··· 240 326 Clone, 241 327 PartialEq, 242 328 Eq, 243 - jacquard_derive::IntoStatic, 244 329 )] 245 330 #[serde(tag = "error", content = "message")] 246 331 #[serde(bound(deserialize = "'de: 'a"))] ··· 265 350 266 351 impl Error for ResolveHandleError<'_> {} 267 352 353 + impl IntoStatic for ResolveHandleError<'_> { 354 + type Output = ResolveHandleError<'static>; 355 + 356 + fn into_static(self) -> Self::Output { 357 + match self { 358 + Self::HandleNotFound(msg) => ResolveHandleError::HandleNotFound(msg.into_static()), 359 + } 360 + } 361 + } 362 + 268 363 /// Response marker for com.atproto.identity.resolveHandle. 269 364 pub struct ResolveHandleResponse; 270 365 ··· 293 388 Clone, 294 389 PartialEq, 295 390 Eq, 296 - jacquard_derive::IntoStatic, 297 391 )] 298 392 #[serde(rename_all = "camelCase")] 299 393 pub struct ResolveDid<'a> { ··· 301 395 pub did: Did<'a>, 302 396 } 303 397 398 + impl IntoStatic for ResolveDid<'_> { 399 + type Output = ResolveDid<'static>; 400 + 401 + fn into_static(self) -> Self::Output { 402 + ResolveDid { 403 + did: self.did.into_static(), 404 + } 405 + } 406 + } 407 + 304 408 /// Output for com.atproto.identity.resolveDid. 305 409 #[derive( 306 410 Serialize, ··· 309 413 Clone, 310 414 PartialEq, 311 415 Eq, 312 - jacquard_derive::IntoStatic, 313 416 )] 314 417 #[serde(rename_all = "camelCase")] 315 418 pub struct ResolveDidOutput<'a> { ··· 317 420 pub did_doc: Data<'a>, 318 421 } 319 422 423 + impl IntoStatic for ResolveDidOutput<'_> { 424 + type Output = ResolveDidOutput<'static>; 425 + 426 + fn into_static(self) -> Self::Output { 427 + ResolveDidOutput { 428 + did_doc: self.did_doc.into_static(), 429 + } 430 + } 431 + } 432 + 320 433 /// Error type for com.atproto.identity.resolveDid. 321 434 #[derive( 322 435 Serialize, ··· 325 438 Clone, 326 439 PartialEq, 327 440 Eq, 328 - jacquard_derive::IntoStatic, 329 441 )] 330 442 #[serde(tag = "error", content = "message")] 331 443 #[serde(bound(deserialize = "'de: 'a"))] ··· 359 471 360 472 impl Error for ResolveDidError<'_> {} 361 473 474 + impl IntoStatic for ResolveDidError<'_> { 475 + type Output = ResolveDidError<'static>; 476 + 477 + fn into_static(self) -> Self::Output { 478 + match self { 479 + Self::DidNotFound(msg) => ResolveDidError::DidNotFound(msg.into_static()), 480 + Self::DidDeactivated(msg) => ResolveDidError::DidDeactivated(msg.into_static()), 481 + } 482 + } 483 + } 484 + 362 485 /// Response marker for com.atproto.identity.resolveDid. 363 486 pub struct ResolveDidResponse; 364 487 ··· 383 506 mod tests { 384 507 use super::*; 385 508 use crate::IntoStatic; 386 - use serde_json::json; 387 509 388 510 #[test] 389 511 fn test_list_records_serializes() {