Skip to content

Commit 74e4573

Browse files
committed
Add Tid::now() constructor
1 parent a28705d commit 74e4573

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

atrium-api/src/types/string.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,22 @@ use regex::Regex;
99
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
1010
use std::{cmp, ops::Deref, str::FromStr, sync::OnceLock};
1111

12+
// Reference: https://github.com/bluesky-social/indigo/blob/9e3b84fdbb20ca4ac397a549e1c176b308f7a6e1/repo/tid.go#L11-L19
13+
fn s32_encode(mut i: u64) -> String {
14+
const S32_CHAR: &[u8] = b"234567abcdefghijklmnopqrstuvwxyz";
15+
16+
let mut s = String::new();
17+
for _ in 0..13 {
18+
let c = i & 0x1F;
19+
s.push(S32_CHAR[c as usize] as char);
20+
21+
i >>= 5;
22+
}
23+
24+
// Reverse the string to convert it to big-endian format.
25+
s.as_str().chars().rev().collect()
26+
}
27+
1228
/// Common trait implementations for Lexicon string formats that are newtype wrappers
1329
/// around `String`.
1430
macro_rules! string_newtype {
@@ -410,7 +426,7 @@ impl Serialize for Language {
410426

411427
/// A [Timestamp Identifier].
412428
///
413-
/// [Timestamp Identifier]: https://atproto.com/specs/record-key#record-key-type-tid
429+
/// [Timestamp Identifier]: https://atproto.com/specs/tid
414430
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)]
415431
#[serde(transparent)]
416432
pub struct Tid(String);
@@ -436,6 +452,19 @@ impl Tid {
436452
}
437453
}
438454

455+
/// Construct a new timestamp with the specified clock ID.
456+
///
457+
/// Clock IDs 0-31 can be used as an ad-hoc clock ID if you are not concerned
458+
/// with this parameter.
459+
pub fn now(cid: u32) -> Self {
460+
let now = chrono::Utc::now().timestamp_micros() as u64;
461+
462+
// The TID is laid out as follows:
463+
// 0TTTTTTTTTTTTTTT TTTTTTTTTTTTTTTT TTTTTTTTTTTTTTTT TTTTTTCCCCCCCCCC
464+
let tid = (now << 10) & 0x7FFF_FFFF_FFFF_FC00 | (cid as u64) & 0x3FF;
465+
Self(s32_encode(tid))
466+
}
467+
439468
/// Returns the TID as a string slice.
440469
pub fn as_str(&self) -> &str {
441470
self.0.as_str()
@@ -766,6 +795,12 @@ mod tests {
766795
}
767796
}
768797

798+
#[test]
799+
fn tid_encode() {
800+
assert_eq!(s32_encode(0), "2222222222222");
801+
assert_eq!(s32_encode(1), "2222222222223");
802+
}
803+
769804
#[test]
770805
fn valid_tid() {
771806
for valid in ["3jzfcijpj2z2a", "7777777777777", "3zzzzzzzzzzzz"] {

0 commit comments

Comments
 (0)