vapoursynth4_rs/map/
key.rs1use std::{
2 ffi::{CStr, CString, c_char},
3 fmt::{Debug, Display},
4 ops::Deref,
5 ptr,
6};
7
8use thiserror::Error;
9
10#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
11#[repr(transparent)]
12pub struct Key {
13 inner: CString,
14}
15
16impl Key {
17 pub fn new<T>(val: T) -> Result<Self, InvalidKey>
22 where
23 T: Into<Vec<u8>>,
24 {
25 let mut val: Vec<u8> = val.into();
26 if let Some(i) = val.iter().position(|&c| c == 0) {
27 val.drain(i..);
28 }
29 if val.iter().all(|&c| c.is_ascii_alphanumeric() || c == b'_') {
30 val.push(0);
31 Ok(Self {
32 inner: unsafe { CString::from_vec_with_nul_unchecked(val) },
33 })
34 } else {
35 Err(InvalidKey)
36 }
37 }
38}
39
40impl Deref for Key {
41 type Target = KeyStr;
42
43 fn deref(&self) -> &Self::Target {
44 unsafe { KeyStr::from_cstr_unchecked(self.inner.as_c_str()) }
46 }
47}
48
49impl From<&KeyStr> for Key {
50 fn from(value: &KeyStr) -> Self {
51 Self {
52 inner: value.inner.into(),
53 }
54 }
55}
56
57impl Display for Key {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 unsafe { f.write_str(std::str::from_utf8_unchecked(self.inner.as_bytes())) }
61 }
62}
63
64#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
65#[repr(transparent)]
66pub struct KeyStr {
67 inner: CStr,
68}
69
70impl KeyStr {
71 #[must_use]
72 pub const fn from_cstr(str: &CStr) -> &Self {
75 let mut i = 0;
76 let slice = str.to_bytes();
77 while i < slice.len() {
78 let c = slice[i];
79 assert!(
80 c.is_ascii_alphanumeric() || c == b'_',
81 "Key must be alphanumeric or underscore"
82 );
83 i += 1;
84 }
85 unsafe { Self::from_cstr_unchecked(str) }
86 }
87
88 #[must_use]
89 pub const unsafe fn from_cstr_unchecked(str: &CStr) -> &Self {
92 unsafe { &*(ptr::from_ref(str) as *const KeyStr) }
93 }
94
95 pub(crate) unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self {
96 Self::from_cstr(unsafe { CStr::from_ptr(ptr) })
97 }
98}
99
100impl Deref for KeyStr {
101 type Target = CStr;
102
103 fn deref(&self) -> &Self::Target {
104 &self.inner
105 }
106}
107
108impl Display for KeyStr {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 unsafe { f.write_str(std::str::from_utf8_unchecked(self.inner.to_bytes())) }
111 }
112}
113
114#[macro_export]
115macro_rules! key {
116 ($s:expr) => {
117 const { $crate::map::KeyStr::from_cstr($s) }
118 };
119}
120
121#[derive(Debug, Error)]
122#[error("Key is invalid. Only ascii alphanumeric or underscore is allowed.")]
123pub struct InvalidKey;