rdf_fusion_functions/scalar/strings/
encode_for_uri.rs1use crate::scalar::dispatch::dispatch_unary_owned_typed_value;
2use crate::scalar::sparql_op_impl::{
3 ScalarSparqlOpImpl, create_typed_value_sparql_op_impl,
4};
5use crate::scalar::{ScalarSparqlOp, ScalarSparqlOpSignature, SparqlOpArity};
6use rdf_fusion_encoding::typed_value::TypedValueEncoding;
7use rdf_fusion_extensions::functions::BuiltinName;
8use rdf_fusion_extensions::functions::FunctionName;
9use rdf_fusion_model::{SimpleLiteral, ThinError, TypedValue, TypedValueRef};
10
11#[derive(Debug, Hash, PartialEq, Eq)]
12pub struct EncodeForUriSparqlOp;
13
14impl Default for EncodeForUriSparqlOp {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl EncodeForUriSparqlOp {
21 const NAME: FunctionName = FunctionName::Builtin(BuiltinName::EncodeForUri);
22
23 pub fn new() -> Self {
24 Self {}
25 }
26}
27
28impl ScalarSparqlOp for EncodeForUriSparqlOp {
29 fn name(&self) -> &FunctionName {
30 &Self::NAME
31 }
32
33 fn signature(&self) -> ScalarSparqlOpSignature {
34 ScalarSparqlOpSignature::default_with_arity(SparqlOpArity::Fixed(1))
35 }
36
37 fn typed_value_encoding_op(
38 &self,
39 ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
40 Some(create_typed_value_sparql_op_impl(|args| {
41 dispatch_unary_owned_typed_value(
42 &args.args[0],
43 |value| {
44 let string = match value {
45 TypedValueRef::SimpleLiteral(value) => value.value,
46 TypedValueRef::LanguageStringLiteral(value) => value.value,
47 _ => return ThinError::expected(),
48 };
49
50 let mut result = Vec::with_capacity(string.len());
53 for c in string.bytes() {
54 match c {
55 b'A'..=b'Z'
56 | b'a'..=b'z'
57 | b'0'..=b'9'
58 | b'-'
59 | b'_'
60 | b'.'
61 | b'~' => result.push(c),
62 _ => {
63 result.push(b'%');
64 let high = c / 16;
65 let low = c % 16;
66 result.push(if high < 10 {
67 b'0' + high
68 } else {
69 b'A' + (high - 10)
70 });
71 result.push(if low < 10 {
72 b'0' + low
73 } else {
74 b'A' + (low - 10)
75 });
76 }
77 }
78 }
79
80 let value = String::from_utf8(result)?;
81 Ok(TypedValue::SimpleLiteral(SimpleLiteral { value }))
82 },
83 ThinError::expected,
84 )
85 }))
86 }
87}