toad_writable/
lib.rs

1//! This microcrate provides a struct implementing [`core::fmt::Write`] for all [`toad_array::Array`]s
2
3// docs
4#![doc(html_root_url = "https://docs.rs/toad-writable/0.0.0")]
5#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
6// -
7// style
8#![allow(clippy::unused_unit)]
9// -
10// deny
11#![deny(missing_docs)]
12#![deny(missing_debug_implementations)]
13#![deny(missing_copy_implementations)]
14#![cfg_attr(not(test), deny(unsafe_code))]
15// -
16// warnings
17#![cfg_attr(not(test), warn(unreachable_pub))]
18// -
19// features
20#![cfg_attr(not(feature = "std"), no_std)]
21
22#[cfg(feature = "alloc")]
23extern crate alloc as std_alloc;
24
25use core::fmt::Display;
26use core::ops::{Deref, DerefMut};
27
28use toad_array::Array;
29
30/// Newtype wrapper that adds a blanket implementation of [`core::fmt::Write`]
31/// to any & all [`Array`]s
32///
33/// This allows alloc-less format strings:
34/// ```
35/// use core::fmt::Write;
36///
37/// use toad_array::Array;
38/// use toad_writable::Writable;
39///
40/// let mut stringish = Writable::from(vec![]);
41///
42/// write!(stringish, "Your number is: {}", 123).ok();
43/// assert_eq!(stringish.as_str(), "Your number is: 123");
44/// ```
45#[derive(Clone, Copy, Debug, Default)]
46pub struct Writable<A: Array<Item = u8>>(A);
47
48impl<A: Array<Item = u8>> Writable<A> {
49  /// Attempt to read the data in the buffer
50  /// as a UTF8 string slice
51  pub fn as_str(&self) -> &str {
52    core::str::from_utf8(self).unwrap()
53  }
54
55  /// Get a slice of the byte buffer
56  pub fn as_slice(&self) -> &[u8] {
57    &self.0
58  }
59
60  /// Get a mutable slice of the byte buffer
61  pub fn as_mut_slice(&mut self) -> &mut [u8] {
62    &mut self.0
63  }
64
65  /// Get the collection wrapped by this `Writable`
66  pub fn unwrap(self) -> A {
67    self.0
68  }
69}
70
71impl<A> Display for Writable<A> where A: Array<Item = u8>
72{
73  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74    write!(f, "{}", self.as_str())
75  }
76}
77
78impl<A: Array<Item = u8>> From<A> for Writable<A> {
79  fn from(a: A) -> Self {
80    Self(a)
81  }
82}
83
84impl<A: Array<Item = u8>> Deref for Writable<A> {
85  type Target = A;
86
87  fn deref(&self) -> &A {
88    &self.0
89  }
90}
91
92impl<A: Array<Item = u8>> DerefMut for Writable<A> {
93  fn deref_mut(&mut self) -> &mut A {
94    &mut self.0
95  }
96}
97
98impl<A: Array<Item = u8>> AsRef<str> for Writable<A> {
99  fn as_ref(&self) -> &str {
100    self.as_str()
101  }
102}
103
104impl<A: Array<Item = u8>> core::fmt::Write for Writable<A> {
105  fn write_str(&mut self, s: &str) -> core::fmt::Result {
106    match A::CAPACITY {
107      | Some(max) if max < self.len() + s.len() => Err(core::fmt::Error),
108      | _ => {
109        self.extend(s.bytes());
110        Ok(())
111      },
112    }
113  }
114}