libpijul_compat/backend/
small_string.rs

1use sanakirja::{Alignment, Representable};
2use std;
3pub const MAX_LENGTH: usize = 255;
4
5/// A string of length at most 255, with a more compact on-disk
6/// encoding.
7#[repr(packed)]
8pub struct SmallString {
9    pub len: u8,
10    pub str: [u8; MAX_LENGTH],
11}
12
13/// A borrowed version of `SmallStr`.
14#[derive(Clone, Copy)]
15pub struct SmallStr<'a>(*const u8, std::marker::PhantomData<&'a ()>);
16
17impl Clone for SmallString {
18    fn clone(&self) -> Self {
19        Self::from_str(self.as_str())
20    }
21}
22
23impl std::fmt::Debug for SmallString {
24    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
25        self.as_small_str().fmt(fmt)
26    }
27}
28
29impl<'a> PartialEq for SmallStr<'a> {
30    fn eq(&self, x: &SmallStr) -> bool {
31        self.as_str().eq(x.as_str())
32    }
33}
34impl<'a> Eq for SmallStr<'a> {}
35
36impl PartialEq for SmallString {
37    fn eq(&self, x: &SmallString) -> bool {
38        self.as_str().eq(x.as_str())
39    }
40}
41impl Eq for SmallString {}
42
43impl<'a> std::hash::Hash for SmallStr<'a> {
44    fn hash<H: std::hash::Hasher>(&self, x: &mut H) {
45        self.as_str().hash(x)
46    }
47}
48
49impl std::hash::Hash for SmallString {
50    fn hash<H: std::hash::Hasher>(&self, x: &mut H) {
51        self.as_str().hash(x)
52    }
53}
54
55impl<'a> PartialOrd for SmallStr<'a> {
56    fn partial_cmp(&self, x: &SmallStr) -> Option<std::cmp::Ordering> {
57        self.as_str().partial_cmp(x.as_str())
58    }
59}
60impl<'a> Ord for SmallStr<'a> {
61    fn cmp(&self, x: &SmallStr) -> std::cmp::Ordering {
62        self.as_str().cmp(x.as_str())
63    }
64}
65
66impl<'a> std::fmt::Debug for SmallStr<'a> {
67    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
68        self.as_str().fmt(fmt)
69    }
70}
71
72impl SmallString {
73    pub fn len(&self) -> usize {
74        self.len as usize
75    }
76
77    pub fn is_empty(&self) -> bool {
78        self.len() == 0
79    }
80
81    pub fn from_str(s: &str) -> Self {
82        let mut b = SmallString {
83            len: s.len() as u8,
84            str: [0; MAX_LENGTH],
85        };
86        b.clone_from_str(s);
87        b
88    }
89    pub fn clone_from_str(&mut self, s: &str) {
90        self.len = s.len() as u8;
91        (&mut self.str[..s.len()]).copy_from_slice(s.as_bytes());
92    }
93    pub fn clear(&mut self) {
94        self.len = 0;
95    }
96    pub fn push_str(&mut self, s: &str) {
97        let l = self.len as usize;
98        assert!(l + s.len() <= 0xff);
99        (&mut self.str[l..l + s.len()]).copy_from_slice(s.as_bytes());
100        self.len += s.len() as u8;
101    }
102
103    pub fn as_small_str(&self) -> SmallStr {
104        SmallStr(
105            self as *const SmallString as *const u8,
106            std::marker::PhantomData,
107        )
108    }
109
110    pub fn as_str(&self) -> &str {
111        self.as_small_str().as_str()
112    }
113}
114
115impl<'a> SmallStr<'a> {
116    pub fn is_empty(&self) -> bool {
117        self.len() == 0
118    }
119
120    pub fn len(&self) -> usize {
121        unsafe { (*self.0) as usize }
122    }
123
124    pub fn as_str(&self) -> &'a str {
125        unsafe {
126            std::str::from_utf8_unchecked(std::slice::from_raw_parts(
127                self.0.offset(1),
128                *self.0 as usize,
129            ))
130        }
131    }
132    pub fn to_unsafe(&self) -> UnsafeSmallStr {
133        UnsafeSmallStr(self.0)
134    }
135    pub unsafe fn from_unsafe(u: UnsafeSmallStr) -> Self {
136        SmallStr(u.0, std::marker::PhantomData)
137    }
138    pub fn to_owned(&self) -> SmallString {
139        SmallString::from_str(self.as_str())
140    }
141}
142
143#[derive(Clone, Copy)]
144pub struct UnsafeSmallStr(*const u8);
145impl std::fmt::Debug for UnsafeSmallStr {
146    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
147        unsafe { SmallStr::from_unsafe(*self).fmt(fmt) }
148    }
149}
150
151impl Representable for UnsafeSmallStr {
152    fn alignment() -> Alignment {
153        Alignment::B1
154    }
155    fn onpage_size(&self) -> u16 {
156        unsafe {
157            let len = (*self.0) as u16;
158            1 + len
159        }
160    }
161    unsafe fn write_value(&self, p: *mut u8) {
162        trace!("write_value {:?}", p);
163        std::ptr::copy(self.0, p, self.onpage_size() as usize)
164    }
165    unsafe fn read_value(p: *const u8) -> Self {
166        trace!("read_value {:?}", p);
167        UnsafeSmallStr(p)
168    }
169    unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {
170        let a = SmallStr::from_unsafe(UnsafeSmallStr(self.0));
171        let b = SmallStr::from_unsafe(x);
172        a.as_str().cmp(b.as_str())
173    }
174    type PageOffsets = std::iter::Empty<u64>;
175    fn page_offsets(&self) -> Self::PageOffsets {
176        std::iter::empty()
177    }
178}