1use crate::compiler::prelude::*;
2
3fn upcase(value: &Value) -> Resolved {
4 Ok(value.try_bytes_utf8_lossy()?.to_uppercase().into())
5}
6
7#[derive(Clone, Copy, Debug)]
8pub struct Upcase;
9
10impl Function for Upcase {
11 fn identifier(&self) -> &'static str {
12 "upcase"
13 }
14
15 fn usage(&self) -> &'static str {
16 "Upcases `value`, where upcase is defined according to the Unicode Derived Core Property Uppercase."
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 examples(&self) -> &'static [Example] {
28 &[example! {
29 title: "Upcase a string",
30 source: r#"upcase("Hello, World!")"#,
31 result: Ok("HELLO, WORLD!"),
32 }]
33 }
34
35 fn parameters(&self) -> &'static [Parameter] {
36 const PARAMETERS: &[Parameter] = &[Parameter::required(
37 "value",
38 kind::BYTES,
39 "The string to convert to uppercase.",
40 )];
41 PARAMETERS
42 }
43
44 fn compile(
45 &self,
46 _state: &state::TypeState,
47 _ctx: &mut FunctionCompileContext,
48 arguments: ArgumentList,
49 ) -> Compiled {
50 let value = arguments.required("value");
51
52 Ok(UpcaseFn { value }.as_expr())
53 }
54}
55
56#[derive(Debug, Clone)]
57struct UpcaseFn {
58 value: Box<dyn Expression>,
59}
60
61impl FunctionExpression for UpcaseFn {
62 fn resolve(&self, ctx: &mut Context) -> Resolved {
63 let value = self.value.resolve(ctx)?;
64 upcase(&value)
65 }
66
67 fn type_def(&self, _: &TypeState) -> TypeDef {
68 TypeDef::bytes().infallible()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::value;
76
77 test_function![
78 upcase => Upcase;
79
80 simple {
81 args: func_args![value: "FOO 2 bar"],
82 want: Ok(value!("FOO 2 BAR")),
83 tdef: TypeDef::bytes(),
84 }
85 ];
86}