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 {
73 let mut i = 0;
74 let slice = str.to_bytes();
75 while i < slice.len() {
76 let c = slice[i];
77 assert!(
78 c.is_ascii_alphanumeric() || c == b'_',
79 "Key must be alphanumeric or underscore"
80 );
81 i += 1;
82 }
83 unsafe { Self::from_cstr_unchecked(str) }
84 }
85
86 #[must_use]
87 pub const unsafe fn from_cstr_unchecked(str: &CStr) -> &Self {
90 unsafe { &*(ptr::from_ref(str) as *const KeyStr) }
91 }
92
93 pub(crate) unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self {
94 Self::from_cstr(unsafe { CStr::from_ptr(ptr) })
95 }
96}
97
98impl Deref for KeyStr {
99 type Target = CStr;
100
101 fn deref(&self) -> &Self::Target {
102 &self.inner
103 }
104}
105
106impl Display for KeyStr {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 unsafe { f.write_str(std::str::from_utf8_unchecked(self.inner.to_bytes())) }
109 }
110}
111
112#[macro_export]
113macro_rules! key {
114 ($s:expr) => {
115 const { $crate::map::KeyStr::from_cstr($s) }
116 };
117}
118
119#[derive(Debug, Error)]
120#[error("Key is invalid. Only ascii alphanumeric or underscore is allowed.")]
121pub struct InvalidKey;