lightweight com.atproto.sync.listReposByCollection
45
fork

Configure Feed

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

it's possible these lifetimes make sense

phil 380c6bc3 bec3f003

+39 -27
+1 -1
src/mst/mod.rs
··· 6 6 7 7 use std::collections::BTreeMap; 8 8 9 - #[derive(Debug)] 9 + #[derive(Debug, Clone)] 10 10 pub struct Span<T: Ord> { 11 11 gap_before: bool, 12 12 things: BTreeMap<T, bool>, // gap after
+38 -26
src/mst/slice_tricks.rs
··· 25 25 /// 26 26 /// there is probably a nice way to implement PartialOrd, but... we're just 27 27 /// going to tack a `/` on the end and call it a day 28 - #[derive(Debug, PartialEq, Eq)] 29 - pub struct SortableCollection(Nsid<'static>); 28 + #[derive(Debug, Clone, PartialEq, Eq)] 29 + pub struct SortableCollection<'a>(Nsid<'a>); 30 30 31 - impl Ord for SortableCollection { 31 + impl Ord for SortableCollection<'_> { 32 32 fn cmp(&self, other: &Self) -> Ordering { 33 33 let (s, o) = (&self.0.as_str(), &other.0.as_str()); 34 34 ··· 48 48 } 49 49 } 50 50 51 - impl PartialOrd for SortableCollection { 51 + impl PartialOrd for SortableCollection<'_> { 52 52 fn partial_cmp(&self, other: &SortableCollection) -> Option<Ordering> { 53 53 Some(self.cmp(other)) 54 54 } 55 55 } 56 56 57 - impl<'a> From<&'a Nsid<'a>> for SortableCollection { 58 - fn from(nsid: &'a Nsid<'a>) -> SortableCollection { 59 - let s = nsid.to_string(); 60 - SortableCollection(s.into()) 57 + impl<'a> From<&'a Nsid<'a>> for SortableCollection<'a> { 58 + fn from(nsid: &'a Nsid<'a>) -> SortableCollection<'a> { 59 + SortableCollection(nsid.clone()) 61 60 } 62 61 } 63 62 64 - impl From<&SortableCollection> for Nsid<'static> { 63 + impl<'a> From<Nsid<'a>> for SortableCollection<'a> { 64 + fn from(nsid: Nsid<'a>) -> SortableCollection<'a> { 65 + SortableCollection(nsid) 66 + } 67 + } 68 + 69 + impl<'a> From<&'a SortableCollection<'a>> for Nsid<'a> { 65 70 /// go back to jacquard typed (unchecked) 66 71 /// 67 72 /// panics if missing the '/' suffix or if the nsid got messed up 68 - fn from(SortableCollection(s): &SortableCollection) -> Nsid<'static> { 73 + fn from(SortableCollection(s): &'a SortableCollection<'a>) -> Nsid<'a> { 69 74 s.clone() 70 75 } 71 76 } 72 77 73 78 /// represent the collections across a whole, possibly sparse, repo 74 - type CollectionSpan = Span<SortableCollection>; 79 + type CollectionSpan<'a> = Span<SortableCollection<'a>>; 75 80 76 - impl CollectionSpan { 81 + impl<'a> CollectionSpan<'a> { 77 82 /// get a list of NSIDs if the span has no gaps 78 83 /// 79 84 /// a CollectionSpan can be complete even if it contains gaps, as long as 80 85 /// those gaps are *within* collection-bounding keys 81 - fn complete(&self) -> Option<BTreeSet<Nsid<'static>>> { 82 - self.is_complete() 83 - .then(|| self.things.keys().map(Into::into).collect()) 86 + fn complete(&self) -> Option<BTreeSet<Nsid<'a>>> { 87 + if self.is_complete() { 88 + return Some( 89 + self.things 90 + .keys() 91 + .map(|c| c.0.clone()) // unsatisfying :/ 92 + .collect(), 93 + ); 94 + } 95 + None 84 96 } 85 97 /// whether it's possible that this span covers some NSIDs 86 98 /// 87 99 /// each NSID from the set must either be in span, or in a gap of it 88 - pub fn could_cover(&self, collections: &BTreeSet<Nsid<'_>>) -> bool { 100 + pub fn could_cover(&self, collections: &BTreeSet<Nsid<'a>>) -> bool { 89 101 let mut candidates = collections.iter().map(Into::<SortableCollection>::into); 90 102 let Some(mut candidate) = candidates.next() else { 91 103 return true; // empty set can always be covered, even by a zero-gap ··· 134 146 } 135 147 136 148 /// extract a span of collection NSIDs (with possible gaps) from a CAR slice 137 - fn span_from_slice(car: &mut MemCar) -> Result<CollectionSpan> { 149 + fn span_from_slice(car: &mut MemCar) -> Result<CollectionSpan<'static>> { 138 150 let mut prev_gap = false; 139 151 let mut prev_collection = None; 140 152 ··· 152 164 let (nsid_str, _) = key.split_once('/').ok_or_else(|| { 153 165 MstSliceTricksError::InvalidData(format!("missing '/' in key: {key}")) 154 166 })?; 155 - let collection: Nsid<'_> = nsid_str 167 + let collection: Nsid<'static> = nsid_str 156 168 .parse() 157 169 .map_err(|e| MstSliceTricksError::InvalidData(format!("nsid parse: {e}")))?; 158 170 ··· 164 176 } 165 177 166 178 prev_gap = false; 167 - prev_collection = Some((&collection).into()); 179 + prev_collection = Some(collection.into()); 168 180 } 169 181 170 182 if let Some(prev) = prev_collection { ··· 197 209 /// the CAR slice provably covered every collection! 198 210 Complete(BTreeSet<Nsid<'static>>), 199 211 /// the repo is likely very small 200 - Tiny(CollectionSpan), 212 + Tiny(CollectionSpan<'static>), 201 213 /// non-tiny incomplete car, collections we know about 202 - Otherwise(CollectionSpan), 214 + Otherwise(CollectionSpan<'static>), 203 215 } 204 216 205 217 /// Assess a CAR slice ··· 225 237 #[cfg(test)] 226 238 mod tests { 227 239 use super::*; 228 - use jacquard_common::types::string::Nsid; 240 + use jacquard_common::{IntoStatic, types::string::Nsid}; 229 241 use std::collections::BTreeSet; 230 242 231 243 // --- helpers shared across all tests --- ··· 234 246 Nsid::new_owned(s).unwrap() 235 247 } 236 248 237 - fn make_span(gap_before: bool, things: &[(&str, bool)]) -> CollectionSpan { 249 + fn make_span(gap_before: bool, things: &[(&str, bool)]) -> CollectionSpan<'static> { 238 250 CollectionSpan { 239 251 gap_before, 240 252 things: things 241 253 .iter() 242 254 .map(|(k, v)| { 243 255 let nsid = Nsid::from(k.to_string()); 244 - ((&nsid).into(), *v) 256 + (nsid.into_static().into(), *v) 245 257 }) 246 258 .collect(), 247 259 } ··· 268 280 Ordering::Greater, 269 281 ), // the surprising one: `/` always follows nsid, sorts after `.` 270 282 ] { 271 - let us_nsid: SortableCollection = (&nsid(us)).into(); 272 - let them_nsid: SortableCollection = (&nsid(them)).into(); 283 + let us_nsid: SortableCollection = nsid(us).into(); 284 + let them_nsid: SortableCollection = nsid(them).into(); 273 285 assert_eq!( 274 286 us_nsid.cmp(&them_nsid), 275 287 expected,