surrealdb_types/value/
file.rs1use serde::{Deserialize, Serialize};
2
3use crate::sql::{SqlFormat, ToSql};
4
5#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
11pub struct File {
12 pub bucket: String,
14 pub key: String,
16}
17
18impl File {
19 pub fn new<B: Into<String>, K: Into<String>>(bucket: B, key: K) -> Self {
21 let bucket: String = bucket.into();
22 let key: String = key.into();
23
24 let key = if key.starts_with("/") {
25 key
26 } else {
27 format!("/{key}")
28 };
29
30 Self {
31 bucket,
32 key,
33 }
34 }
35
36 pub fn bucket(&self) -> &str {
38 &self.bucket
39 }
40
41 pub fn key(&self) -> &str {
44 &self.key
45 }
46}
47
48impl ToSql for crate::File {
49 fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
50 f.push_str("f\"");
51 f.push_str(&fmt_inner(&self.bucket, true));
52 f.push(':');
53 f.push_str(&fmt_inner(&self.key, false));
54 f.push('"');
55 }
56}
57
58fn fmt_inner(v: &str, escape_slash: bool) -> String {
59 v.chars()
60 .flat_map(|c| {
61 if c.is_ascii_alphanumeric()
62 || matches!(c, '-' | '_' | '.')
63 || (!escape_slash && c == '/')
64 {
65 vec![c]
66 } else {
67 vec!['\\', c]
68 }
69 })
70 .collect::<String>()
71}
72
73#[cfg(feature = "arbitrary")]
74mod arb {
75 use super::*;
76 impl<'a> arbitrary::Arbitrary<'a> for File {
77 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
78 static CHAR: [u8; 56] = [
79 b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n',
80 b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'A', b'B',
81 b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P',
82 b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'_', b'-', b'.', b'/',
83 ];
84
85 let mut bucket = String::new();
86 bucket.push(CHAR[u.int_in_range(0u8..=54)? as usize] as char);
89 for _ in 0..u.arbitrary_len::<u8>()? {
90 bucket.push(CHAR[u.int_in_range(0u8..=54)? as usize] as char);
91 }
92 let mut key = "/".to_string();
93 for _ in 0..u.arbitrary_len::<u8>()? {
94 key.push(CHAR[u.int_in_range(0u8..=55)? as usize] as char);
95 }
96 Ok(File {
97 bucket,
98 key,
99 })
100 }
101 }
102}