1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! A no_std-friendly data-writing "sink" trait which allows for convenient expression
16 //! of "write me into a limited-size buffer"-type methods on traits.
17 
18 #![cfg_attr(not(feature = "std"), no_std)]
19 
20 /// An append-only, limited-size collection.
21 pub trait Sink<T> {
22     /// Returns `Some` if the slice was appended, `None` otherwise, in which case nothing was written
try_extend_from_slice(&mut self, items: &[T]) -> Option<()>23     fn try_extend_from_slice(&mut self, items: &[T]) -> Option<()>;
24 
25     /// Returns `Some` if the item could be pushed, `None` otherwise
try_push(&mut self, item: T) -> Option<()>26     fn try_push(&mut self, item: T) -> Option<()>;
27 
28     /// Uses the given [`SinkWriter`] to write to this sink.
try_extend_from_writer<W: SinkWriter<DataType = T>>(&mut self, writer: W) -> Option<()> where Self: Sized,29     fn try_extend_from_writer<W: SinkWriter<DataType = T>>(&mut self, writer: W) -> Option<()>
30     where
31         Self: Sized,
32     {
33         writer.write_payload(self)
34     }
35 }
36 
37 /// A use-once trait (like `FnOnce`) which represents some
38 /// code which writes data to a [`Sink`].
39 pub trait SinkWriter {
40     /// The type of data being written to the [`Sink`].
41     type DataType;
42 
43     /// Returns `Some` if all data was successfully written to the [`Sink`],
44     /// but if doing so failed at any point, returns `None`. If this method
45     /// fails, the contents of the [`Sink`] should be considered to be invalid.
write_payload<S: Sink<Self::DataType> + ?Sized>(self, sink: &mut S) -> Option<()>46     fn write_payload<S: Sink<Self::DataType> + ?Sized>(self, sink: &mut S) -> Option<()>;
47 }
48 
49 impl<T, A> Sink<T> for tinyvec::ArrayVec<A>
50 where
51     A: tinyvec::Array<Item = T>,
52     T: Clone,
53 {
try_extend_from_slice(&mut self, items: &[T]) -> Option<()>54     fn try_extend_from_slice(&mut self, items: &[T]) -> Option<()> {
55         if items.len() > (self.capacity() - self.len()) {
56             return None;
57         }
58         // won't panic: just checked the length
59         self.extend_from_slice(items);
60         Some(())
61     }
62 
try_push(&mut self, item: T) -> Option<()>63     fn try_push(&mut self, item: T) -> Option<()> {
64         // tinyvec uses None to indicate success, whereas for our limited purposes we want the
65         // opposite
66         match tinyvec::ArrayVec::try_push(self, item) {
67             None => Some(()),
68             Some(_) => None,
69         }
70     }
71 }
72 
73 #[cfg(feature = "std")]
74 impl<T: Clone> Sink<T> for std::vec::Vec<T> {
try_extend_from_slice(&mut self, items: &[T]) -> Option<()>75     fn try_extend_from_slice(&mut self, items: &[T]) -> Option<()> {
76         self.extend_from_slice(items);
77         Some(())
78     }
79 
try_push(&mut self, item: T) -> Option<()>80     fn try_push(&mut self, item: T) -> Option<()> {
81         self.push(item);
82         Some(())
83     }
84 }
85