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