threadloom_dom/
storage.rs1use serde::{de::DeserializeOwned, Serialize};
2
3pub fn url_encode(s: &str) -> String {
6 const SAFE: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~";
7 let mut out = String::with_capacity(s.len());
8 for b in s.bytes() {
9 if SAFE.contains(&b) {
10 out.push(b as char);
11 } else {
12 out.push('%');
13 out.push(char::from_digit((b >> 4) as u32, 16).unwrap().to_ascii_uppercase());
14 out.push(char::from_digit((b & 0x0f) as u32, 16).unwrap().to_ascii_uppercase());
15 }
16 }
17 out
18}
19
20pub fn url_decode(s: &str) -> Option<String> {
21 let bytes = s.as_bytes();
22 let mut out: Vec<u8> = Vec::with_capacity(s.len());
23 let mut i = 0;
24 while i < bytes.len() {
25 if bytes[i] == b'%' && i + 2 < bytes.len() {
26 let hi = char::from(bytes[i + 1]).to_digit(16)?;
27 let lo = char::from(bytes[i + 2]).to_digit(16)?;
28 out.push(((hi << 4) | lo) as u8);
29 i += 3;
30 } else {
31 out.push(bytes[i]);
32 i += 1;
33 }
34 }
35 String::from_utf8(out).ok()
36}
37
38pub fn set_json_cookie<T: Serialize>(name: &str, value: &T, max_age: u32) {
39 if let Ok(json) = serde_json::to_string(value) {
40 let enc = url_encode(&json);
41 crate::set_cookie!(name, enc, max_age);
42 }
43}
44
45pub fn get_json_cookie<T: DeserializeOwned>(name: &str) -> Option<T> {
46 let raw = crate::get_cookie!(name)?;
47 if raw.is_empty() {
48 return None;
49 }
50 let json = url_decode(&raw)?;
51 serde_json::from_str(&json).ok()
52}