robinpath_modules/modules/
uuid_mod.rs1use robinpath::{RobinPath, Value};
2
3pub fn register(rp: &mut RobinPath) {
4 rp.register_builtin("uuid.v4", |_args, _| {
5 Ok(Value::String(gen_v4()))
6 });
7
8 rp.register_builtin("uuid.isValid", |args, _| {
9 let s = args.first().map(|v| v.to_display_string()).unwrap_or_default();
10 let re = regex::Regex::new(
11 r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
12 )
13 .unwrap();
14 Ok(Value::Bool(re.is_match(&s)))
15 });
16
17 rp.register_builtin("uuid.version", |args, _| {
18 let s = args.first().map(|v| v.to_display_string()).unwrap_or_default();
19 if s.len() >= 15 {
20 if let Some(ch) = s.chars().nth(14) {
21 if let Some(v) = ch.to_digit(16) {
22 return Ok(Value::Number(v as f64));
23 }
24 }
25 }
26 Ok(Value::Null)
27 });
28
29 rp.register_builtin("uuid.parse", |args, _| {
30 let s = args.first().map(|v| v.to_display_string()).unwrap_or_default();
31 let mut obj = indexmap::IndexMap::new();
32 if s.len() >= 36 {
33 let version = s.chars().nth(14).and_then(|c| c.to_digit(16)).unwrap_or(0);
34 obj.insert("version".to_string(), Value::Number(version as f64));
35 let variant_char = s.chars().nth(19).unwrap_or('0');
36 let variant_val = variant_char.to_digit(16).unwrap_or(0);
37 let variant = if variant_val & 0x8 == 0 {
38 "NCS"
39 } else if variant_val & 0xC == 0x8 {
40 "RFC4122"
41 } else if variant_val & 0xE == 0xC {
42 "Microsoft"
43 } else {
44 "Future"
45 };
46 obj.insert("variant".to_string(), Value::String(variant.to_string()));
47 let hex = s.replace('-', "");
48 obj.insert("hex".to_string(), Value::String(hex));
49 }
50 Ok(Value::Object(obj))
51 });
52
53 rp.register_builtin("uuid.generate", |args, _| {
54 let count = args.first().map(|v| v.to_number() as usize).unwrap_or(1);
55 if count == 1 {
56 return Ok(Value::String(gen_v4()));
57 }
58 let uuids: Vec<Value> = (0..count).map(|_| Value::String(gen_v4())).collect();
59 Ok(Value::Array(uuids))
60 });
61
62 rp.register_builtin("uuid.nil", |_args, _| {
63 Ok(Value::String(
64 "00000000-0000-0000-0000-000000000000".to_string(),
65 ))
66 });
67}
68
69fn gen_v4() -> String {
70 use std::time::{SystemTime, UNIX_EPOCH};
72 let seed = SystemTime::now()
73 .duration_since(UNIX_EPOCH)
74 .unwrap_or_default()
75 .as_nanos();
76 let mut state = seed ^ (std::ptr::from_ref(&seed) as u128).wrapping_mul(6364136223846793005);
78 let mut bytes = [0u8; 16];
79 for byte in &mut bytes {
80 state = state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
81 *byte = (state >> 33) as u8;
82 }
83 bytes[6] = (bytes[6] & 0x0f) | 0x40;
85 bytes[8] = (bytes[8] & 0x3f) | 0x80;
87
88 format!(
89 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
90 bytes[0], bytes[1], bytes[2], bytes[3],
91 bytes[4], bytes[5],
92 bytes[6], bytes[7],
93 bytes[8], bytes[9],
94 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
95 )
96}