1use fluent_uri::{
3 encoding::{encoder::Fragment, EStr, Encoder},
4 Uri, UriRef,
5};
6use once_cell::sync::Lazy;
7
8use crate::Error;
9pub use fluent_uri::encoding::encoder::Path;
10
11pub fn resolve_against(base: &Uri<&str>, uri: &str) -> Result<Uri<String>, Error> {
17 if uri.starts_with('#') && base.as_str().ends_with(uri) {
18 return Ok(base.to_owned());
19 }
20 Ok(UriRef::parse(uri)
21 .map_err(|error| Error::uri_reference_parsing_error(uri, error))?
22 .resolve_against(base)
23 .map_err(|error| Error::uri_resolving_error(uri, *base, error))?
24 .normalize())
25}
26
27pub fn from_str(uri: &str) -> Result<Uri<String>, Error> {
33 let uriref = UriRef::parse(uri)
34 .map_err(|error| Error::uri_reference_parsing_error(uri, error))?
35 .normalize();
36 if uriref.has_scheme() {
37 Ok(Uri::try_from(uriref.as_str())
38 .map_err(|error| Error::uri_parsing_error(uriref.as_str(), error))?
39 .into())
40 } else {
41 Ok(uriref
42 .resolve_against(&DEFAULT_ROOT_URI.borrow())
43 .map_err(|error| Error::uri_resolving_error(uri, DEFAULT_ROOT_URI.borrow(), error))?)
44 }
45}
46
47pub(crate) static DEFAULT_ROOT_URI: Lazy<Uri<String>> =
48 Lazy::new(|| Uri::parse("json-schema:///".to_string()).expect("Invalid URI"));
49
50pub type EncodedString = EStr<Fragment>;
51
52pub fn encode_to(input: &str, buffer: &mut String) {
54 const HEX_TABLE: [u8; 512] = {
55 const HEX_DIGITS: &[u8; 16] = b"0123456789ABCDEF";
56
57 let mut i = 0;
58 let mut table = [0; 512];
59 while i < 256 {
60 table[i * 2] = HEX_DIGITS[i >> 4];
61 table[i * 2 + 1] = HEX_DIGITS[i & 0b1111];
62 i += 1;
63 }
64 table
65 };
66
67 for ch in input.chars() {
68 if Path::TABLE.allows(ch) {
69 buffer.push(ch);
70 } else {
71 for x in ch.encode_utf8(&mut [0; 4]).bytes() {
72 buffer.push('%');
73 buffer.push(HEX_TABLE[x as usize * 2] as char);
74 buffer.push(HEX_TABLE[x as usize * 2 + 1] as char);
75 }
76 }
77 }
78}