1use crate::compiler::prelude::*;
2
3fn downcase(value: &Value) -> Resolved {
4 Ok(value.try_bytes_utf8_lossy()?.to_lowercase().into())
5}
6
7#[derive(Clone, Copy, Debug)]
8pub struct Downcase;
9
10impl Function for Downcase {
11 fn identifier(&self) -> &'static str {
12 "downcase"
13 }
14
15 fn usage(&self) -> &'static str {
16 "Downcases the `value` string, where downcase is defined according to the Unicode Derived Core Property Lowercase."
17 }
18
19 fn category(&self) -> &'static str {
20 Category::String.as_ref()
21 }
22
23 fn return_kind(&self) -> u16 {
24 kind::BYTES
25 }
26
27 fn parameters(&self) -> &'static [Parameter] {
28 const PARAMETERS: &[Parameter] = &[Parameter::required(
29 "value",
30 kind::BYTES,
31 "The string to convert to lowercase.",
32 )];
33 PARAMETERS
34 }
35
36 fn compile(
37 &self,
38 _state: &state::TypeState,
39 _ctx: &mut FunctionCompileContext,
40 arguments: ArgumentList,
41 ) -> Compiled {
42 let value = arguments.required("value");
43
44 Ok(DowncaseFn { value }.as_expr())
45 }
46
47 fn examples(&self) -> &'static [Example] {
48 &[
49 example! {
50 title: "Downcase a string",
51 source: r#"downcase("Hello, World!")"#,
52 result: Ok("hello, world!"),
53 },
54 example! {
55 title: "Downcase with number",
56 source: r#"downcase("FOO 2 BAR")"#,
57 result: Ok("foo 2 bar"),
58 },
59 ]
60 }
61}
62
63#[derive(Debug, Clone)]
64struct DowncaseFn {
65 value: Box<dyn Expression>,
66}
67
68impl FunctionExpression for DowncaseFn {
69 fn resolve(&self, ctx: &mut Context) -> Resolved {
70 let value = self.value.resolve(ctx)?;
71 downcase(&value)
72 }
73
74 fn type_def(&self, _: &state::TypeState) -> TypeDef {
75 TypeDef::bytes().infallible()
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::value;
83
84 test_function![
85 downcase => Downcase;
86
87 simple {
88 args: func_args![value: "FOO 2 bar"],
89 want: Ok(value!("foo 2 bar")),
90 tdef: TypeDef::bytes(),
91 }
92 ];
93}