inspect_format/container/
common.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub trait BlockContainer {
6    type Data;
7    type ShareableData;
8
9    /// Returns the size of the container.
10    fn len(&self) -> usize;
11
12    /// Returns whether the container is empty or not.
13    fn is_empty(&self) -> bool {
14        self.len() == 0
15    }
16}
17
18/// Trait implemented by an Inspect container that can be read from.
19pub trait ReadBytes: BlockContainer {
20    /// Returns a slice of the given size at the given offset if one exists of the exact size.
21    fn get_slice_at(&self, offset: usize, size: usize) -> Option<&[u8]>;
22
23    /// Returns a slice of the given size at the beginning of the container if one exists of the
24    /// exact size.
25    #[inline]
26    fn get_slice(&self, size: usize) -> Option<&[u8]> {
27        self.get_slice_at(0, size)
28    }
29
30    /// Returns a reference to the value at the give offset, if one exists.
31    #[inline]
32    fn get_value<T: ContainerValue>(&self, offset: usize) -> Option<&T> {
33        self.get_slice_at(offset, std::mem::size_of::<T>()).map(|slice| {
34            let ptr = slice.as_ptr() as *const T;
35            // SAFETY: our get_slice_at implementations are guaranteed to validate there's a valid
36            // slice.
37            unsafe { &*ptr }
38        })
39    }
40}
41
42pub trait CopyBytes: BlockContainer {
43    fn copy_bytes_at(&self, offset: usize, dst: &mut [u8]);
44
45    fn copy_bytes(&self, dst: &mut [u8]) {
46        self.copy_bytes_at(0, dst)
47    }
48}
49
50pub trait ContainerValue: private::Sealed {}
51
52mod private {
53    pub trait Sealed {}
54}
55
56macro_rules! impl_container_value {
57    ($($type:ty),*) => {
58        $(
59            impl private::Sealed for $type {}
60            impl ContainerValue for $type {}
61        )*
62    };
63}
64
65impl_container_value!(u8, u16, u32, u64, i64, f64);
66
67/// Trait implemented by container to which bytes can be written.
68pub trait WriteBytes {
69    /// Returns an exclusive reference to a slice of the given size at the given offset if one
70    /// exists of the exact size.
71    fn get_slice_mut_at(&mut self, offset: usize, size: usize) -> Option<&mut [u8]>;
72
73    /// Returns an exclusive reference to a slice of the given size at the beginning of the
74    /// container if one exists of the exact size.
75    #[inline]
76    fn get_slice_mut(&mut self, size: usize) -> Option<&mut [u8]> {
77        self.get_slice_mut_at(0, size)
78    }
79
80    #[inline]
81    fn copy_from_slice_at(&mut self, offset: usize, bytes: &[u8]) {
82        // TODO: error
83        if let Some(slice) = self.get_slice_mut_at(offset, bytes.len()) {
84            slice.copy_from_slice(bytes);
85        }
86    }
87
88    #[inline]
89    fn copy_from_slice(&mut self, bytes: &[u8]) {
90        self.copy_from_slice_at(0, bytes);
91    }
92
93    /// Returns an exclusive reference to the value at the give offset, if one exists.
94    #[inline]
95    fn get_value_mut<T: ContainerValue>(&mut self, offset: usize) -> Option<&mut T> {
96        self.get_slice_mut_at(offset, std::mem::size_of::<T>()).map(|slice| {
97            let ptr = slice.as_mut_ptr() as *mut T;
98            // SAFETY: our get_slice_at implementations are guaranteed to validate there's a valid
99            // slice.
100            unsafe { &mut *ptr }
101        })
102    }
103
104    #[inline]
105    fn set_value<T: ContainerValue>(&mut self, offset: usize, value: T) {
106        // TODO: error
107        if let Some(value_ref) = self.get_value_mut(offset) {
108            *value_ref = value;
109        }
110    }
111}
112
113impl BlockContainer for Vec<u8> {
114    type Data = Self;
115    type ShareableData = ();
116
117    /// The number of bytes in the buffer.
118    #[inline]
119    fn len(&self) -> usize {
120        self.as_slice().len()
121    }
122}
123
124impl ReadBytes for Vec<u8> {
125    #[inline]
126    fn get_slice_at(&self, offset: usize, size: usize) -> Option<&[u8]> {
127        self.as_slice().get_slice_at(offset, size)
128    }
129}
130
131impl CopyBytes for Vec<u8> {
132    #[inline]
133    fn copy_bytes_at(&self, offset: usize, dst: &mut [u8]) {
134        if let Some(slice) = self.as_slice().get_slice_at(offset, dst.len()) {
135            dst.copy_from_slice(slice);
136        }
137    }
138}
139
140impl BlockContainer for [u8] {
141    type Data = ();
142    type ShareableData = ();
143
144    #[inline]
145    fn len(&self) -> usize {
146        <[u8]>::len(self)
147    }
148}
149
150impl ReadBytes for [u8] {
151    #[inline]
152    fn get_slice_at(&self, offset: usize, size: usize) -> Option<&[u8]> {
153        let upper_bound = offset.checked_add(size)?;
154        if offset >= self.len() || upper_bound > self.len() {
155            return None;
156        }
157        Some(&self[offset..upper_bound])
158    }
159}
160
161impl<const N: usize> BlockContainer for [u8; N] {
162    type Data = Self;
163    type ShareableData = ();
164
165    /// The number of bytes in the buffer.
166    #[inline]
167    fn len(&self) -> usize {
168        self.as_slice().len()
169    }
170}
171
172impl<const N: usize> ReadBytes for [u8; N] {
173    #[inline]
174    fn get_slice_at(&self, offset: usize, size: usize) -> Option<&[u8]> {
175        self.as_slice().get_slice_at(offset, size)
176    }
177}
178
179/// Trait implemented by an Inspect container that can be written to.
180impl<const N: usize> WriteBytes for [u8; N] {
181    #[inline]
182    fn get_slice_mut_at(&mut self, offset: usize, size: usize) -> Option<&mut [u8]> {
183        if offset >= self.len() {
184            return None;
185        }
186        let upper_bound = offset.checked_add(size)?;
187        if upper_bound > self.len() {
188            return None;
189        }
190        Some(&mut self[offset..upper_bound])
191    }
192}