1use crate::{Archived, FixedIsize, FixedUsize};
4use core::{mem, ptr, slice, str};
5
6const OFFSET_BYTES: usize = mem::size_of::<FixedIsize>();
7
8#[derive(Clone, Copy)]
9#[repr(C)]
10struct OutOfLineRepr {
11 len: Archived<usize>,
12 offset: [u8; OFFSET_BYTES],
15}
16
17pub const INLINE_CAPACITY: usize = mem::size_of::<OutOfLineRepr>() - 1;
19
20#[derive(Clone, Copy)]
21#[repr(C)]
22struct InlineRepr {
23 bytes: [u8; INLINE_CAPACITY],
24 len: u8,
25}
26
27pub union ArchivedStringRepr {
29 out_of_line: OutOfLineRepr,
30 inline: InlineRepr,
31}
32
33impl ArchivedStringRepr {
34 #[inline]
36 pub fn is_inline(&self) -> bool {
37 unsafe { self.inline.len & 0x80 == 0 }
38 }
39
40 #[inline]
46 pub unsafe fn out_of_line_offset(&self) -> isize {
47 FixedIsize::from_le_bytes(self.out_of_line.offset) as isize
48 }
49
50 #[inline]
52 pub fn as_ptr(&self) -> *const u8 {
53 unsafe {
54 if self.is_inline() {
55 self.inline.bytes.as_ptr()
56 } else {
57 (self as *const Self)
58 .cast::<u8>()
59 .offset(self.out_of_line_offset())
60 }
61 }
62 }
63
64 #[inline]
66 pub fn as_mut_ptr(&mut self) -> *mut u8 {
67 unsafe {
68 if self.is_inline() {
69 self.inline.bytes.as_mut_ptr()
70 } else {
71 (self as *mut Self)
72 .cast::<u8>()
73 .offset(self.out_of_line_offset())
74 }
75 }
76 }
77
78 #[inline]
80 pub fn len(&self) -> usize {
81 unsafe {
82 if self.is_inline() {
83 self.inline.len as usize
84 } else {
85 from_archived!(self.out_of_line.len) as usize
86 }
87 }
88 }
89
90 #[inline]
92 pub fn is_empty(&self) -> bool {
93 self.len() == 0
94 }
95
96 #[cfg(feature = "validation")]
98 #[inline]
99 pub fn as_str_ptr(&self) -> *const str {
100 ptr_meta::from_raw_parts(self.as_ptr().cast(), self.len())
101 }
102
103 #[inline]
105 pub fn bytes(&self) -> &[u8] {
106 unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
107 }
108
109 #[inline]
111 pub fn bytes_mut(&mut self) -> &mut [u8] {
112 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
113 }
114
115 #[inline]
117 pub fn as_str(&self) -> &str {
118 unsafe { str::from_utf8_unchecked(self.bytes()) }
119 }
120
121 #[inline]
123 pub fn as_mut_str(&mut self) -> &mut str {
124 unsafe { str::from_utf8_unchecked_mut(self.bytes_mut()) }
125 }
126
127 #[inline]
134 pub unsafe fn emplace_inline(value: &str, out: *mut Self) {
135 let out_bytes = ptr::addr_of_mut!((*out).inline.bytes);
136 ptr::copy_nonoverlapping(value.as_bytes().as_ptr(), out_bytes.cast(), value.len());
137
138 let out_len = ptr::addr_of_mut!((*out).inline.len);
139 *out_len = value.len() as u8;
140 }
141
142 #[inline]
151 pub unsafe fn emplace_out_of_line(value: &str, pos: usize, target: usize, out: *mut Self) {
152 let out_len = ptr::addr_of_mut!((*out).out_of_line.len);
153 out_len.write(to_archived!(value.len() as FixedUsize));
154
155 let out_offset = ptr::addr_of_mut!((*out).out_of_line.offset);
156 let offset = crate::rel_ptr::signed_offset(pos, target).unwrap();
157 *out_offset = (offset as FixedIsize).to_le_bytes();
158 }
159}