pebble_skip/standard_c/
mod.rs1use pebble_sys::standard_c::memory::c_str;
2
3use crate::Box;
4use core::{
5 convert::{TryFrom, TryInto},
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8 slice, str,
9};
10
11pub mod memory;
12
13#[allow(non_camel_case_types)]
14pub type void = pebble_sys::standard_c::memory::void;
15
16#[repr(transparent)]
29pub struct CStr<T: Storage>(PhantomData<T>, str);
30
31pub struct Heap(!);
32pub struct Stack(!);
33pub struct Static(!);
34
35mod private {
36 use super::{Heap, Stack, Static};
37
38 pub trait Sealed {}
39 impl Sealed for Heap {}
40 impl Sealed for Stack {}
41 impl Sealed for Static {}
42}
43
44pub trait Storage: private::Sealed {}
45impl Storage for Heap {}
46impl Storage for Stack {}
47impl Storage for Static {}
48
49pub trait NotStack: Storage {}
50impl NotStack for Heap {}
51impl NotStack for Static {}
52
53trait AsCStr {
54 type Storage: Storage;
55 fn as_c_str(&self) -> Result<&CStr<Self::Storage>, ()>;
56}
57
58impl<'a> TryFrom<Box<'a, str>> for Box<'a, CStr<Heap>> {
59 type Error = ();
60
61 fn try_from(value: Box<str>) -> Result<Self, Self::Error> {
62 match value.ends_with('\0') {
63 true => {
64 Ok(unsafe { Box::from_raw(&mut *(Box::leak(value) as *mut _ as *mut CStr<Heap>)) })
65 }
66 false => Err(()),
67 }
68 }
69}
70
71impl TryFrom<&'static str> for &'static CStr<Static> {
72 type Error = ();
73
74 fn try_from(value: &'static str) -> Result<Self, Self::Error> {
75 match value.ends_with('\0') {
76 true => Ok(unsafe { &*(value as *const _ as *const CStr<Static>) }),
77 false => Err(()),
78 }
79 }
80}
81
82impl TryFrom<&'static mut str> for &'static mut CStr<Static> {
83 type Error = ();
84
85 fn try_from(value: &'static mut str) -> Result<Self, Self::Error> {
86 match value.ends_with('\0') {
87 true => Ok(unsafe { &mut *(value as *mut _ as *mut CStr<Static>) }),
88 false => Err(()),
89 }
90 }
91}
92
93impl<'a> TryFrom<&'a str> for &'a CStr<Stack> {
94 type Error = ();
95
96 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
97 match value.ends_with('\0') {
98 true => Ok(unsafe { &*(value as *const _ as *const CStr<Stack>) }),
99 false => Err(()),
100 }
101 }
102}
103
104impl<'a> TryFrom<&'a mut str> for &'a mut CStr<Stack> {
105 type Error = ();
106
107 fn try_from(value: &'a mut str) -> Result<Self, Self::Error> {
108 match value.ends_with('\0') {
109 true => Ok(unsafe { &mut *(value as *mut _ as *mut CStr<Stack>) }),
110 false => Err(()),
111 }
112 }
113}
114
115impl<'a> From<Box<'a, CStr<Heap>>> for Box<'a, str> {
116 fn from(value: Box<'a, CStr<Heap>>) -> Self {
117 unsafe { Box::from_raw(&mut *(Box::leak(value) as *mut _ as *mut str)) }
118 }
119}
120
121impl<T: Storage> Deref for CStr<T> {
122 type Target = str;
123
124 fn deref(&self) -> &Self::Target {
125 let s = unsafe { &*(self as *const _ as *const str) };
126 &s[..s.len() - 1]
127 }
128}
129
130impl<T: Storage> DerefMut for CStr<T> {
131 fn deref_mut(&mut self) -> &mut Self::Target {
132 let s = unsafe { &mut *(self as *mut _ as *mut str) };
133 let len = s.len();
134 &mut s[..len - 1]
135 }
136}
137
138impl<T: Storage> CStr<T> {
139 #[must_use]
140 pub fn as_c_str(&self) -> &c_str {
141 unsafe { &*(self as *const _ as *const c_str) }
142 }
143
144 #[must_use]
145 pub fn as_c_str_mut(&mut self) -> &mut c_str {
146 unsafe { &mut *(self as *mut _ as *mut c_str) }
147 }
148}
149
150impl<T: Storage> CStr<T> {
151 #[must_use]
155 pub unsafe fn from_zero_terminated_unchecked(str: &str) -> &Self {
156 &*(str as *const _ as *const CStr<T>)
157 }
158
159 #[must_use]
163 pub unsafe fn from_zero_terminated_unchecked_mut(str: &mut str) -> &mut Self {
164 &mut *(str as *mut _ as *mut CStr<T>)
165 }
166
167 #[must_use]
171 pub unsafe fn from_raw_parts_mut(c_str: &mut c_str, len: usize) -> &mut Self {
172 let slice = slice::from_raw_parts_mut(c_str as *mut _ as *mut u8, len);
173 let str = str::from_utf8_unchecked_mut(slice);
174 &mut *(str as *mut _ as *mut CStr<T>)
175 }
176}
177
178impl CStr<Stack> {
179 pub fn try_from_stack(str: &str) -> Result<&Self, ()> {
183 str.try_into()
184 }
185}
186
187impl CStr<Static> {
188 pub fn try_from_static(str: &'static str) -> Result<&'static Self, ()> {
192 str.try_into()
193 }
194
195 #[must_use]
199 pub unsafe fn from_static_zero_terminated_unchecked(str: &'static str) -> &'static Self {
200 CStr::<Static>::from_zero_terminated_unchecked(str)
201 }
202}