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

add _idx suffix for clarity (thanks maxh!) +fwd->o

"forward links" now align a little on the "other link" terminology used in the client-facing api

(kind of regret "other" as a term but oh well!)

authored by bad-example.com and committed by tangled.org 2a143bba e12537a8

+39 -31
+17 -14
constellation/src/storage/mem_store.rs
··· 257 // extract parts form composite cursor 258 let cursor = match after { 259 Some(a) => { 260 - let (b, f) = a.split_once(',').ok_or(anyhow!("invalid cursor format"))?; 261 - let b = b 262 .parse::<u64>() 263 .map_err(|e| anyhow!("invalid cursor.0: {e}"))?; 264 - let f = f 265 .parse::<u64>() 266 .map_err(|e| anyhow!("invalid cursor.1: {e}"))?; 267 Some(ManyToManyCursor { 268 - backlink: b, 269 - forward_link: f, 270 }) 271 } 272 None => None, ··· 283 let mut items: Vec<(usize, usize, ManyToManyItem)> = Vec::new(); 284 285 // iterate backwards (who linked to the target?) 286 - for (linker_idx, (did, rkey)) in linkers 287 .iter() 288 .enumerate() 289 .filter_map(|(i, opt)| opt.as_ref().map(|v| (i, v))) 290 - .skip_while(|(linker_idx, _)| cursor.is_some_and(|c| *linker_idx < c.backlink as usize)) 291 .filter(|(_, (did, _))| filter_dids.is_empty() || filter_dids.contains(did)) 292 { 293 let Some(links) = data.links.get(did).and_then(|m| { ··· 299 continue; 300 }; 301 302 - // iterate forward (which of these links point to the __other__ target?) 303 - for (link_idx, (_, fwd_target)) in links 304 .iter() 305 .enumerate() 306 .filter(|(_, (p, t))| { 307 *p == path_to_other && (filter_targets.is_empty() || filter_targets.contains(t)) 308 }) 309 - .skip_while(|(link_idx, _)| { 310 cursor.is_some_and(|c| { 311 - linker_idx == c.backlink as usize && *link_idx <= c.forward_link as usize 312 }) 313 }) 314 .take(limit as usize + 1 - items.len()) ··· 321 }, 322 other_subject: fwd_target.0.clone(), 323 }; 324 - items.push((linker_idx, link_idx, item)); 325 } 326 327 // page full - eject ··· 331 } 332 333 let next = (items.len() > limit as usize).then(|| { 334 - let (l, f, _) = items[limit as usize - 1]; 335 - format!("{l},{f}") 336 }); 337 338 let items = items
··· 257 // extract parts form composite cursor 258 let cursor = match after { 259 Some(a) => { 260 + let (b, o) = a.split_once(',').ok_or(anyhow!("invalid cursor format"))?; 261 + let backlink_idx = b 262 .parse::<u64>() 263 .map_err(|e| anyhow!("invalid cursor.0: {e}"))?; 264 + let other_link_idx = o 265 .parse::<u64>() 266 .map_err(|e| anyhow!("invalid cursor.1: {e}"))?; 267 Some(ManyToManyCursor { 268 + backlink_idx, 269 + other_link_idx, 270 }) 271 } 272 None => None, ··· 283 let mut items: Vec<(usize, usize, ManyToManyItem)> = Vec::new(); 284 285 // iterate backwards (who linked to the target?) 286 + for (backlink_idx, (did, rkey)) in linkers 287 .iter() 288 .enumerate() 289 .filter_map(|(i, opt)| opt.as_ref().map(|v| (i, v))) 290 + .skip_while(|(backlink_idx, _)| { 291 + cursor.is_some_and(|c| *backlink_idx < c.backlink_idx as usize) 292 + }) 293 .filter(|(_, (did, _))| filter_dids.is_empty() || filter_dids.contains(did)) 294 { 295 let Some(links) = data.links.get(did).and_then(|m| { ··· 301 continue; 302 }; 303 304 + // iterate forward (which of these links point to the "other" target?) 305 + for (other_link_idx, (_, fwd_target)) in links 306 .iter() 307 .enumerate() 308 .filter(|(_, (p, t))| { 309 *p == path_to_other && (filter_targets.is_empty() || filter_targets.contains(t)) 310 }) 311 + .skip_while(|(other_link_idx, _)| { 312 cursor.is_some_and(|c| { 313 + backlink_idx == c.backlink_idx as usize 314 + && *other_link_idx <= c.other_link_idx as usize 315 }) 316 }) 317 .take(limit as usize + 1 - items.len()) ··· 324 }, 325 other_subject: fwd_target.0.clone(), 326 }; 327 + items.push((backlink_idx, other_link_idx, item)); 328 } 329 330 // page full - eject ··· 334 } 335 336 let next = (items.len() > limit as usize).then(|| { 337 + let (b, o, _) = items[limit as usize - 1]; 338 + format!("{b},{o}") 339 }); 340 341 let items = items
+2 -2
constellation/src/storage/mod.rs
··· 41 42 #[derive(Copy, Clone, Debug)] 43 struct ManyToManyCursor { 44 - backlink: u64, 45 - forward_link: u64, 46 } 47 48 /// A paged collection whose keys are sorted instead of indexed
··· 41 42 #[derive(Copy, Clone, Debug)] 43 struct ManyToManyCursor { 44 + backlink_idx: u64, 45 + other_link_idx: u64, 46 } 47 48 /// A paged collection whose keys are sorted instead of indexed
+20 -15
constellation/src/storage/rocks_store.rs
··· 1156 let cursor = match after { 1157 Some(a) => { 1158 let (b, f) = a.split_once(',').ok_or(anyhow!("invalid cursor format"))?; 1159 - let b = b 1160 .parse::<u64>() 1161 .map_err(|e| anyhow!("invalid cursor.0: {e}"))?; 1162 - let f = f 1163 .parse::<u64>() 1164 .map_err(|e| anyhow!("invalid cursor.1: {e}"))?; 1165 Some(ManyToManyCursor { 1166 - backlink: b, 1167 - forward_link: f, 1168 }) 1169 } 1170 None => None, ··· 1195 let mut items: Vec<(usize, usize, ManyToManyItem)> = Vec::new(); 1196 1197 // iterate backlinks (who linked to the target?) 1198 - for (linker_idx, (did_id, rkey)) in 1199 - linkers.0.iter().enumerate().skip_while(|(linker_idx, _)| { 1200 - cursor.is_some_and(|c| *linker_idx < c.backlink as usize) 1201 - }) 1202 { 1203 if did_id.is_empty() 1204 || (!filter_did_ids.is_empty() && !filter_did_ids.contains_key(did_id)) ··· 1215 continue; 1216 }; 1217 1218 - // iterate fwd links (which of these links point to the __other__ target?) 1219 - for (link_idx, RecordLinkTarget(_, fwd_target_id)) in links 1220 .0 1221 .into_iter() 1222 .enumerate() ··· 1225 && (filter_to_target_ids.is_empty() 1226 || filter_to_target_ids.contains(target_id)) 1227 }) 1228 - .skip_while(|(link_idx, _)| { 1229 cursor.is_some_and(|c| { 1230 - linker_idx == c.backlink as usize && *link_idx <= c.forward_link as usize 1231 }) 1232 }) 1233 .take(limit as usize + 1 - items.len()) ··· 1254 link_record: record_id, 1255 other_subject: fwd_target_key.0 .0, 1256 }; 1257 - items.push((linker_idx, link_idx, item)); 1258 } 1259 1260 // page full - eject ··· 1273 // forward_link_idx are skipped. This correctly resumes mid-record when 1274 // a single backlinker has multiple forward links at path_to_other. 1275 let next = (items.len() > limit as usize).then(|| { 1276 - let (l, f, _) = items[limit as usize - 1]; 1277 - format!("{l},{f}") 1278 }); 1279 1280 let items = items
··· 1156 let cursor = match after { 1157 Some(a) => { 1158 let (b, f) = a.split_once(',').ok_or(anyhow!("invalid cursor format"))?; 1159 + let backlink_idx = b 1160 .parse::<u64>() 1161 .map_err(|e| anyhow!("invalid cursor.0: {e}"))?; 1162 + let other_link_idx = f 1163 .parse::<u64>() 1164 .map_err(|e| anyhow!("invalid cursor.1: {e}"))?; 1165 Some(ManyToManyCursor { 1166 + backlink_idx, 1167 + other_link_idx, 1168 }) 1169 } 1170 None => None, ··· 1195 let mut items: Vec<(usize, usize, ManyToManyItem)> = Vec::new(); 1196 1197 // iterate backlinks (who linked to the target?) 1198 + for (backlink_idx, (did_id, rkey)) in 1199 + linkers 1200 + .0 1201 + .iter() 1202 + .enumerate() 1203 + .skip_while(|(backlink_idx, _)| { 1204 + cursor.is_some_and(|c| *backlink_idx < c.backlink_idx as usize) 1205 + }) 1206 { 1207 if did_id.is_empty() 1208 || (!filter_did_ids.is_empty() && !filter_did_ids.contains_key(did_id)) ··· 1219 continue; 1220 }; 1221 1222 + // iterate fwd links (which of these links point to the "other" target?) 1223 + for (other_link_idx, RecordLinkTarget(_, fwd_target_id)) in links 1224 .0 1225 .into_iter() 1226 .enumerate() ··· 1229 && (filter_to_target_ids.is_empty() 1230 || filter_to_target_ids.contains(target_id)) 1231 }) 1232 + .skip_while(|(other_link_idx, _)| { 1233 cursor.is_some_and(|c| { 1234 + backlink_idx == c.backlink_idx as usize 1235 + && *other_link_idx <= c.other_link_idx as usize 1236 }) 1237 }) 1238 .take(limit as usize + 1 - items.len()) ··· 1259 link_record: record_id, 1260 other_subject: fwd_target_key.0 .0, 1261 }; 1262 + items.push((backlink_idx, other_link_idx, item)); 1263 } 1264 1265 // page full - eject ··· 1278 // forward_link_idx are skipped. This correctly resumes mid-record when 1279 // a single backlinker has multiple forward links at path_to_other. 1280 let next = (items.len() > limit as usize).then(|| { 1281 + let (b, o, _) = items[limit as usize - 1]; 1282 + format!("{b},{o}") 1283 }); 1284 1285 let items = items