vrl/stdlib/
uuid_from_friendly_id.rs1use crate::compiler::prelude::*;
2use bytes::Bytes;
3
4fn uuid_from_friendly_id(value: &Value) -> Resolved {
5 let mut buf = [0; 36];
6 let value = value.try_bytes_utf8_lossy()?;
7 match base62::decode(value.as_ref()) {
8 Err(err) => Err(format!("failed to decode friendly id: {err}").into()),
9 Ok(w128) => {
10 let uuid = uuid::Uuid::from_u128(w128)
11 .hyphenated()
12 .encode_lower(&mut buf);
13 Ok(Bytes::copy_from_slice(uuid.as_bytes()).into())
14 }
15 }
16}
17
18#[derive(Clone, Copy, Debug)]
19pub struct UuidFromFriendlyId;
20
21impl Function for UuidFromFriendlyId {
22 fn identifier(&self) -> &'static str {
23 "uuid_from_friendly_id"
24 }
25
26 fn usage(&self) -> &'static str {
27 "Convert a Friendly ID (base62 encoding a 128-bit word) to a UUID."
28 }
29
30 fn category(&self) -> &'static str {
31 Category::Random.as_ref()
32 }
33
34 fn internal_failure_reasons(&self) -> &'static [&'static str] {
35 &[
36 "`value` is a string but the text uses characters outside of class [0-9A-Za-z].",
37 "`value` is a base62 encoding of an integer, but the integer is greater than or equal to 2^128.",
38 ]
39 }
40
41 fn return_kind(&self) -> u16 {
42 kind::BYTES
43 }
44
45 fn parameters(&self) -> &'static [Parameter] {
46 const PARAMETERS: &[Parameter] = &[Parameter::required(
47 "value",
48 kind::BYTES,
49 "A string that is a Friendly ID",
50 )];
51 PARAMETERS
52 }
53
54 fn examples(&self) -> &'static [Example] {
55 &[example! {
56 title: "Convert a Friendly ID to a UUID",
57 source: r#"uuid_from_friendly_id!("3s87yEvnmkiPBMHsj8bwwc")"#,
58 result: Ok("7f41deed-d5e2-8b5e-7a13-ab4ff93cfad2"),
59 }]
60 }
61
62 fn compile(
63 &self,
64 _state: &state::TypeState,
65 _ctx: &mut FunctionCompileContext,
66 arguments: ArgumentList,
67 ) -> Compiled {
68 let value = arguments.required("value");
69 Ok(UuidFromFriendlyIdFn { value }.as_expr())
70 }
71}
72
73#[derive(Debug, Clone)]
74struct UuidFromFriendlyIdFn {
75 value: Box<dyn Expression>,
76}
77
78impl FunctionExpression for UuidFromFriendlyIdFn {
79 fn resolve(&self, ctx: &mut Context) -> Resolved {
80 let value = self.value.resolve(ctx)?;
81 uuid_from_friendly_id(&value)
82 }
83
84 fn type_def(&self, _: &TypeState) -> TypeDef {
85 TypeDef::bytes().fallible()
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::value;
93
94 test_function![
95 uuid_from_friendly_id => UuidFromFriendlyId;
96 example_from_docs {
97 args: func_args![value: value!("3s87yEvnmkiPBMHsj8bwwc")],
98 want: Ok(value!("7f41deed-d5e2-8b5e-7a13-ab4ff93cfad2")),
99 tdef: TypeDef::bytes().fallible(),
100 }
101 ];
102}