@@ -0,0 +1,291 @@
use std ::{
sync ::{ Mutex , OnceLock } ,
thread ,
time ::Duration ,
} ;
use thiserror ::Error ;
use time ::UtcDateTime ;
#[ derive(Debug, Error) ]
pub enum UuidV7Error {
#[ error( " UUIDv7 Generator not initialized " ) ]
GeneratorNotInitialized ,
#[ error( " UUIDv7 Node ID exceeded the maximum supports " ) ]
NodeIdExceeded ,
#[ error( " Invalid UUIDv7 string format " ) ]
InvalidStringFormat ,
#[ error( " Invalid Base64 format string " ) ]
InvalidBase64Format ,
}
const EPOCH : i64 = 1645566142222 ; // 自定义纪元: 2022-02-22 22:22:22.222 UTC
const NODE_BITS : u8 = 5 ; // 主机编号容量为0~ 32
const SEQUENCE_BITS : u8 = 18 ; // 每毫秒生成序列号最大为2^18-1, 即262144个
const MAX_NODE_ID : u16 = ( 1 < < NODE_BITS ) - 1 ;
const MAX_SEQUENCE : u32 = ( 1 < < SEQUENCE_BITS ) - 1 ;
const TIMESTAMP_SHIFTS : u8 = NODE_BITS + SEQUENCE_BITS ;
const NODE_SHIFTS : u8 = SEQUENCE_BITS ;
pub struct Uuidv7Generator {
node_id : u16 ,
last_timestamp : i64 ,
sequence : u32 ,
}
#[ allow(dead_code) ]
pub struct Uuidv7Components {
timestamp : i64 , // 毫秒时间戳(相对于自定义纪元)
node_id : u16 , // 5位节点ID
sequence : u32 , // 18位序列号
version : u8 , // 版本号( 应为7)
variant : u8 , // 变体( 应为2, 表示10xx)
raw_bytes : [ u8 ; 16 ] , // 原始字节
}
static GENERATOR : OnceLock < Mutex < Uuidv7Generator > > = OnceLock ::new ( ) ;
/// 获取UUIDv7生成器实例, 如果实例未初始化, 则返回错误。
pub fn generator < ' a > ( ) -> Result < & ' a Mutex < Uuidv7Generator > , UuidV7Error > {
GENERATOR . get ( ) . ok_or ( UuidV7Error ::GeneratorNotInitialized )
}
/// 初始化UUIDv7生成器实例。
///
/// - `node_id`: 节点ID, 取值范围: 0~ 32。
pub fn init_generator ( node_id : u16 ) -> Result < ( ) , UuidV7Error > {
if node_id > MAX_NODE_ID {
return Err ( UuidV7Error ::NodeIdExceeded ) ;
}
GENERATOR
. set ( Mutex ::new ( Uuidv7Generator ::new ( node_id ) ) )
. map_err ( | _ | UuidV7Error ::GeneratorNotInitialized )
}
impl Uuidv7Generator {
pub fn new ( node_id : u16 ) -> Self {
Self {
node_id ,
last_timestamp : EPOCH ,
sequence : 0 ,
}
}
fn now ( & self ) -> i64 {
( UtcDateTime ::now ( ) . unix_timestamp_nanos ( ) / 1_000_000 - EPOCH as i128 ) as i64
}
pub fn next ( & mut self ) -> Uuidv7Components {
let mut now = self . now ( ) ;
if now < self . last_timestamp {
now = self . last_timestamp ;
}
if now = = self . last_timestamp {
self . sequence + = 1 ;
if self . sequence > MAX_SEQUENCE {
thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
now = self . now ( ) ;
self . sequence = 0 ;
}
} else {
self . sequence = 0 ;
}
self . last_timestamp = now ;
Uuidv7Components {
timestamp : now ,
node_id : self . node_id ,
sequence : self . sequence ,
version : 7 ,
variant : 2 ,
raw_bytes : [ 0 ; 16 ] ,
}
}
}
impl Uuidv7Components {
pub fn bytes ( & self ) -> [ u8 ; 16 ] {
let mut uuid = [ 0 u8 ; 16 ] ;
// 时间戳( 48 位)
let timestamp = ( self . timestamp as u64 ) < < TIMESTAMP_SHIFTS ;
let seq_and_node = ( ( self . sequence as u64 ) < < NODE_SHIFTS ) | ( self . node_id as u64 ) ;
// 写入高位时间戳
uuid [ 0 ] = ( timestamp > > 56 ) as u8 ;
uuid [ 1 ] = ( timestamp > > 48 ) as u8 ;
uuid [ 2 ] = ( timestamp > > 40 ) as u8 ;
uuid [ 3 ] = ( timestamp > > 32 ) as u8 ;
uuid [ 4 ] = ( timestamp > > 24 ) as u8 ;
uuid [ 5 ] = ( timestamp > > 16 ) as u8 ;
// 写入低位时间戳 + 版本号( 4 位)
uuid [ 6 ] = ( ( timestamp > > 8 ) as u8 ) | 0x70 ; // version 7
// 写入 seq + node
uuid [ 7 ] = timestamp as u8 ;
uuid [ 8 ] = ( ( seq_and_node > > 16 ) as u8 ) | 0x80 ; // variant 10xx
uuid [ 9 ] = ( seq_and_node > > 8 ) as u8 ;
uuid [ 10 ] = seq_and_node as u8 ;
// 剩余位使用随机数填充
use rand ::RngCore ;
let mut rng = rand ::thread_rng ( ) ;
rng . fill_bytes ( & mut uuid [ 11 .. 16 ] ) ;
uuid
}
pub fn to_base64 ( & self ) -> String {
let uuid = self . bytes ( ) ;
crate ::serialize ::to_base64_str ( uuid )
}
pub fn try_from_base64 < S : AsRef < str > > ( uuid_str : S ) -> Result < Self , UuidV7Error > {
let bytes = crate ::serialize ::from_base64_str ( uuid_str . as_ref ( ) )
. map_err ( | _ | UuidV7Error ::InvalidBase64Format ) ? ;
if bytes . len ( ) ! = 16 {
return Err ( UuidV7Error ::InvalidStringFormat ) ;
}
let mut uuid_bytes = [ 0 u8 ; 16 ] ;
uuid_bytes . copy_from_slice ( & bytes ) ;
Uuidv7Components ::try_from ( uuid_bytes )
}
pub fn to_base36 ( & self ) -> String {
let uuid = self . bytes ( ) ;
crate ::serialize ::base36 ::encode ( & uuid )
}
pub fn try_from_base36 < S : AsRef < str > > ( uuid_str : S ) -> Result < Self , UuidV7Error > {
let bytes = crate ::serialize ::base36 ::decode ( uuid_str . as_ref ( ) )
. map_err ( | _ | UuidV7Error ::InvalidStringFormat ) ? ;
if bytes . len ( ) ! = 16 {
return Err ( UuidV7Error ::InvalidStringFormat ) ;
}
let mut uuid_bytes = [ 0 u8 ; 16 ] ;
uuid_bytes . copy_from_slice ( & bytes ) ;
Uuidv7Components ::try_from ( uuid_bytes )
}
}
impl ToString for Uuidv7Components {
fn to_string ( & self ) -> String {
let uuid = self . bytes ( ) ;
format! (
" {} - {} - {} - {} - {} " ,
hex ::encode ( & uuid [ 0 .. 4 ] ) ,
hex ::encode ( & uuid [ 4 .. 6 ] ) ,
hex ::encode ( & uuid [ 6 .. 8 ] ) ,
hex ::encode ( & uuid [ 8 .. 10 ] ) ,
hex ::encode ( & uuid [ 10 .. 16 ] )
)
}
}
impl PartialEq for Uuidv7Components {
fn eq ( & self , other : & Self ) -> bool {
self . timestamp = = other . timestamp
& & self . node_id = = other . node_id
& & self . sequence = = other . sequence
}
}
impl Eq for Uuidv7Components { }
impl PartialOrd for Uuidv7Components {
fn partial_cmp ( & self , other : & Self ) -> Option < std ::cmp ::Ordering > {
if self . timestamp ! = other . timestamp {
return Some ( self . timestamp . cmp ( & other . timestamp ) ) ;
}
if self . sequence ! = other . sequence {
return Some ( self . sequence . cmp ( & other . sequence ) ) ;
}
if self . node_id ! = other . node_id {
// 注意: 这里与时间戳和序列号不同, node_id的比较逻辑是反的
// 这与Go代码中的Compare方法保持一致
return Some ( other . node_id . cmp ( & self . node_id ) ) ;
}
Some ( std ::cmp ::Ordering ::Equal )
}
}
impl Ord for Uuidv7Components {
fn cmp ( & self , other : & Self ) -> std ::cmp ::Ordering {
self . partial_cmp ( other ) . unwrap ( )
}
}
impl TryFrom < [ u8 ; 16 ] > for Uuidv7Components {
type Error = UuidV7Error ;
fn try_from ( value : [ u8 ; 16 ] ) -> Result < Self , Self ::Error > {
// 提取时间戳( 前48位)
let timestamp = ( ( value [ 0 ] as i64 ) < < 40 )
| ( ( value [ 1 ] as i64 ) < < 32 )
| ( ( value [ 2 ] as i64 ) < < 24 )
| ( ( value [ 3 ] as i64 ) < < 16 )
| ( ( value [ 4 ] as i64 ) < < 8 )
| ( value [ 5 ] as i64 ) ;
// 提取版本号( 第6字节的高4位)
let version = ( value [ 6 ] > > 4 ) as u8 ;
// 提取变体( 第8字节的高2位)
let variant = ( value [ 8 ] > > 6 ) as u8 ;
// 提取序列号和节点ID
// 第8字节的低6位 + 第9字节 + 第10字节组成23位
let seq_and_node = ( ( ( value [ 8 ] & 0x3F ) as i64 ) < < 16 ) // 第8字节低6位
| ( ( value [ 9 ] as i64 ) < < 8 ) // 第9字节
| ( value [ 10 ] as i64 ) ; // 第10字节
// 分离序列号( 高18位) 和节点ID( 低5位)
let sequence = ( seq_and_node > > 5 ) as u32 ;
let node_id = ( seq_and_node & 0x1F ) as u16 ;
Ok ( Uuidv7Components {
timestamp ,
node_id ,
sequence ,
version ,
variant ,
raw_bytes : value ,
} )
}
}
impl TryFrom < String > for Uuidv7Components {
type Error = UuidV7Error ;
fn try_from ( value : String ) -> Result < Self , Self ::Error > {
// 移除连字符
let clean_str = value . replace ( " - " , " " ) ;
// 验证长度
if clean_str . len ( ) ! = 32 {
return Err ( UuidV7Error ::InvalidStringFormat ) ;
}
// 解码十六进制字符串
let bytes = hex ::decode ( & clean_str ) . map_err ( | _ | UuidV7Error ::InvalidStringFormat ) ? ;
// 转换为数组
if bytes . len ( ) ! = 16 {
return Err ( UuidV7Error ::InvalidStringFormat ) ;
}
let mut uuid_bytes = [ 0 u8 ; 16 ] ;
uuid_bytes . copy_from_slice ( & bytes ) ;
Uuidv7Components ::try_from ( uuid_bytes )
}
}