@@ -9,6 +9,22 @@ use regex::Regex;
99use serde:: { de:: Error , Deserialize , Deserializer , Serialize , Serializer } ;
1010use 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`.
1430macro_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) ]
416432pub 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