ferroui_base/utilities/
read_only_memory.rs1use std::fmt;
9use std::rc::Rc;
10
11pub struct ReadOnlyMemory<T> {
15 owner: Option<Rc<[T]>>,
16 start: usize,
17 length: usize,
18}
19
20impl<T> ReadOnlyMemory<T> {
21 pub const fn empty() -> Self {
23 Self { owner: None, start: 0, length: 0 }
24 }
25
26 pub fn new(owner: Rc<[T]>) -> Self {
28 let length = owner.len();
29 Self { owner: Some(owner), start: 0, length }
30 }
31
32 pub fn with_range(owner: Rc<[T]>, start: usize, length: usize) -> Self {
36 assert!(start <= owner.len() && length <= owner.len() - start, "range outside of the buffer");
37 Self { owner: Some(owner), start, length }
38 }
39
40 pub fn from_vec(values: Vec<T>) -> Self {
42 Self::new(Rc::from(values))
43 }
44
45 #[inline]
47 pub fn len(&self) -> usize {
48 self.length
49 }
50
51 #[inline]
53 pub fn is_empty(&self) -> bool {
54 self.length == 0
55 }
56
57 #[inline]
59 pub fn span(&self) -> &[T] {
60 match &self.owner {
61 Some(owner) => &owner[self.start..self.start + self.length],
62 None => &[],
63 }
64 }
65
66 pub fn slice_from(&self, start: usize) -> Self {
70 assert!(start <= self.length, "start outside of the memory");
71 self.slice(start, self.length - start)
72 }
73
74 pub fn slice(&self, start: usize, length: usize) -> Self {
78 assert!(start <= self.length && length <= self.length - start, "range outside of the memory");
79 Self { owner: self.owner.clone(), start: self.start + start, length }
80 }
81
82 #[inline]
84 pub fn offset_in_owner(&self) -> usize {
85 self.start
86 }
87
88 #[inline]
90 pub fn owner(&self) -> Option<&Rc<[T]>> {
91 self.owner.as_ref()
92 }
93
94 pub fn shares_owner_with(&self, other: &Self) -> bool {
96 match (&self.owner, &other.owner) {
97 (Some(a), Some(b)) => Rc::ptr_eq(a, b),
98 (None, None) => true,
99 _ => false,
100 }
101 }
102}
103
104impl<T: Clone> ReadOnlyMemory<T> {
105 pub fn from_slice(values: &[T]) -> Self {
107 Self::new(Rc::from(values))
108 }
109
110 pub fn to_vec(&self) -> Vec<T> {
112 self.span().to_vec()
113 }
114}
115
116impl ReadOnlyMemory<u16> {
117 pub fn from_str(text: &str) -> Self {
119 Self::from_vec(text.encode_utf16().collect())
120 }
121
122 pub fn to_string_lossy(&self) -> String {
124 String::from_utf16_lossy(self.span())
125 }
126}
127
128impl<T> Clone for ReadOnlyMemory<T> {
129 #[inline]
130 fn clone(&self) -> Self {
131 Self { owner: self.owner.clone(), start: self.start, length: self.length }
132 }
133}
134
135impl<T> Default for ReadOnlyMemory<T> {
136 fn default() -> Self {
137 Self::empty()
138 }
139}
140
141impl<T: fmt::Debug> fmt::Debug for ReadOnlyMemory<T> {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.debug_list().entries(self.span()).finish()
144 }
145}
146
147impl<T: PartialEq> PartialEq for ReadOnlyMemory<T> {
151 fn eq(&self, other: &Self) -> bool {
152 self.span() == other.span()
153 }
154}
155
156impl<T> From<Vec<T>> for ReadOnlyMemory<T> {
157 fn from(values: Vec<T>) -> Self {
158 Self::from_vec(values)
159 }
160}
161
162impl<T> From<Rc<[T]>> for ReadOnlyMemory<T> {
163 fn from(values: Rc<[T]>) -> Self {
164 Self::new(values)
165 }
166}
167
168impl From<&str> for ReadOnlyMemory<u16> {
169 fn from(text: &str) -> Self {
170 Self::from_str(text)
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn slices_share_the_buffer() {
180 let memory = ReadOnlyMemory::from_vec(vec![1, 2, 3, 4, 5]);
181 let slice = memory.slice(1, 3);
182 assert_eq!(slice.span(), &[2, 3, 4]);
183 assert_eq!(slice.slice_from(1).span(), &[3, 4]);
184 assert_eq!(slice.offset_in_owner(), 1);
185 assert!(slice.shares_owner_with(&memory));
186 assert!(ReadOnlyMemory::<i32>::empty().is_empty());
187 }
188
189 #[test]
190 fn utf16_round_trip() {
191 let memory = ReadOnlyMemory::<u16>::from_str("a\u{1F600}b");
192 assert_eq!(memory.len(), 4);
193 assert_eq!(memory.to_string_lossy(), "a\u{1F600}b");
194 }
195}