Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
0

Configure Feed

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

prefix type

kinda ugly in the end. boo.

+116 -5
+1 -1
ufos/src/lib.rs
··· 1 1 pub mod consumer; 2 + pub mod db_types; 2 3 pub mod store; 3 - pub mod store_types; 4 4 5 5 use jetstream::events::Cursor; 6 6 use jetstream::exports::{Did, Nsid, RecordKey};
+2 -2
ufos/src/store.rs
··· 130 130 Cursor::from_raw_u64(u64::from_be_bytes(buf)) 131 131 } 132 132 133 - fn by_collection_key_to_bytes(collection: &Nsid, record: &CreateRecord) -> Vec<u8> { 133 + fn by_collection_key_to_bytes(_collection: &Nsid, _record: &CreateRecord) -> Vec<u8> { 134 134 vec![] 135 135 } 136 - fn by_collection_value_to_bytes(record: &CreateRecord) -> Vec<u8> { 136 + fn by_collection_value_to_bytes(_record: &CreateRecord) -> Vec<u8> { 137 137 vec![] 138 138 }
+113 -2
ufos/src/store_types.rs ufos/src/db_types.rs
··· 7 7 encode_to_vec, 8 8 error::{DecodeError, EncodeError}, 9 9 }; 10 + use std::marker::PhantomData; 10 11 use thiserror::Error; 11 12 13 + #[non_exhaustive] 12 14 #[derive(Error, Debug)] 13 15 pub enum EncodingError { 14 16 #[error("failed to parse NSID: {0}")] ··· 29 31 NotUtf8(#[from] std::str::Utf8Error), 30 32 #[error("could not get array from slice: {0}")] 31 33 BadSlice(#[from] std::array::TryFromSliceError), 34 + #[error("wrong static prefix. expected {1:?}, found {0:?}")] 35 + WrongStaticPrefix(String, String), // found, expected 32 36 } 33 37 34 38 fn bincode_conf() -> impl Config { ··· 49 53 } 50 54 51 55 impl<P: DbBytes, S: DbBytes> DbKeyWithPrefix<P, S> { 52 - pub fn to_prefix_bincoded(&self) -> Result<Vec<u8>, EncodingError> { 56 + pub fn from_prefix_to_db_bytes(prefix: &P) -> Result<Vec<u8>, EncodingError> { 57 + prefix.to_db_bytes() 58 + } 59 + pub fn to_prefix_db_bytes(&self) -> Result<Vec<u8>, EncodingError> { 53 60 self.prefix.to_db_bytes() 54 61 } 55 62 } ··· 73 80 } 74 81 } 75 82 83 + trait StaticStr { 84 + fn static_str() -> &'static str; 85 + } 86 + 87 + #[derive(Debug, PartialEq)] 88 + struct DbStaticStr<S: StaticStr> { 89 + marker: PhantomData<S>, 90 + } 91 + impl<S: StaticStr> DbStaticStr<S> { 92 + pub fn new() -> Self { 93 + Self { 94 + marker: PhantomData, 95 + } 96 + } 97 + } 98 + impl<S: StaticStr> DbBytes for DbStaticStr<S> { 99 + fn to_db_bytes(&self) -> Result<Vec<u8>, EncodingError> { 100 + S::static_str().to_string().to_db_bytes() 101 + } 102 + fn from_db_bytes(bytes: &[u8]) -> Result<(Self, usize), EncodingError> { 103 + let (prefix, eaten) = String::from_db_bytes(bytes)?; 104 + if prefix != S::static_str() { 105 + return Err(EncodingError::WrongStaticPrefix( 106 + prefix, 107 + S::static_str().to_string(), 108 + )); 109 + } 110 + Ok(( 111 + Self { 112 + marker: PhantomData, 113 + }, 114 + eaten, 115 + )) 116 + } 117 + } 118 + 76 119 trait Bincodeable: BincodeEncode + BincodeDecode<()> + Sized {} 77 120 78 121 impl<T> DbBytes for T ··· 143 186 144 187 #[cfg(test)] 145 188 mod test { 146 - use super::{Cursor, DbBytes, DbKeyWithPrefix, EncodingError}; 189 + use super::{Cursor, DbBytes, DbKeyWithPrefix, DbStaticStr, EncodingError, StaticStr}; //, DbKeyWithStaticPrefix, DbStaticKeyPrefix}; 147 190 148 191 #[test] 149 192 fn test_string_roundtrip() -> Result<(), EncodingError> { ··· 220 263 "exact bytes consumed for round-trip: {desc}" 221 264 ); 222 265 } 266 + Ok(()) 267 + } 268 + 269 + #[test] 270 + fn test_static_str() -> Result<(), EncodingError> { 271 + #[derive(Debug, PartialEq)] 272 + struct AStaticStr {} 273 + impl StaticStr for AStaticStr { 274 + fn static_str() -> &'static str { 275 + "a static str" 276 + } 277 + } 278 + type ADbStaticStr = DbStaticStr<AStaticStr>; 279 + 280 + let original = ADbStaticStr::new(); 281 + let serialized = original.to_db_bytes()?; 282 + let (restored, bytes_consumed) = ADbStaticStr::from_db_bytes(&serialized)?; 283 + assert_eq!(restored, original); 284 + assert_eq!(bytes_consumed, serialized.len()); 285 + assert!(serialized.starts_with("a static str".as_bytes())); 286 + 287 + Ok(()) 288 + } 289 + 290 + #[test] 291 + fn test_static_str_empty() -> Result<(), EncodingError> { 292 + #[derive(Debug, PartialEq)] 293 + struct AnEmptyStr {} 294 + impl StaticStr for AnEmptyStr { 295 + fn static_str() -> &'static str { 296 + "" 297 + } 298 + } 299 + type ADbEmptyStr = DbStaticStr<AnEmptyStr>; 300 + let original = ADbEmptyStr::new(); 301 + let serialized = original.to_db_bytes()?; 302 + let (restored, bytes_consumed) = ADbEmptyStr::from_db_bytes(&serialized)?; 303 + assert_eq!(restored, original); 304 + assert_eq!(bytes_consumed, serialized.len()); 305 + assert_eq!(serialized, &[0x00]); 306 + 307 + Ok(()) 308 + } 309 + 310 + #[test] 311 + fn test_static_prefix() -> Result<(), EncodingError> { 312 + #[derive(Debug, PartialEq)] 313 + struct AStaticPrefix {} 314 + impl StaticStr for AStaticPrefix { 315 + fn static_str() -> &'static str { 316 + "a static prefix" 317 + } 318 + } 319 + type ADbStaticPrefix = DbStaticStr<AStaticPrefix>; 320 + 321 + type PrefixedCursor = DbKeyWithPrefix<ADbStaticPrefix, Cursor>; 322 + 323 + let original = PrefixedCursor { 324 + prefix: ADbStaticPrefix::new(), 325 + suffix: Cursor::from_raw_u64(123), 326 + }; 327 + let serialized = original.to_db_bytes()?; 328 + let (restored, bytes_consumed) = PrefixedCursor::from_db_bytes(&serialized)?; 329 + assert_eq!(restored, original); 330 + assert_eq!(bytes_consumed, serialized.len()); 331 + assert_eq!(restored.suffix.to_raw_u64(), 123); 332 + assert!(serialized.starts_with("a static prefix".as_bytes())); 333 + 223 334 Ok(()) 224 335 } 225 336 }