1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
#![cfg_attr(not(test), no_std)]
//! `writeable` is a utility crate of the [`ICU4X`] project.
//!
//! It includes [`Writeable`], a core trait representing an object that can be written to a
//! sink implementing std::fmt::Write. It is an alternative to std::fmt::Display with the
//! addition of a function indicating the number of bytes to be written.
//!
//! Writeable improves upon std::fmt::Display in two ways:
//!
//! 1. More efficient, since the sink can pre-allocate bytes.
//! 2. Smaller code, since the format machinery can be short-circuited.
//!
//! Types implementing Writeable have a defaulted writeable_to_string function.
//! If desired, types implementing Writeable can manually implement ToString
//! to wrap writeable_to_string.
//!
//! # Examples
//!
//! ```
//! use writeable::Writeable;
//! use writeable::LengthHint;
//! use writeable::assert_writeable_eq;
//! use std::fmt;
//!
//! struct WelcomeMessage<'s>{
//! pub name: &'s str,
//! }
//!
//! impl<'s> Writeable for WelcomeMessage<'s> {
//! fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
//! sink.write_str("Hello, ")?;
//! sink.write_str(self.name)?;
//! sink.write_char('!')?;
//! Ok(())
//! }
//!
//! fn write_len(&self) -> LengthHint {
//! // "Hello, " + '!' + length of name
//! LengthHint::Exact(8 + self.name.len())
//! }
//! }
//!
//! let message = WelcomeMessage { name: "Alice" };
//! assert_writeable_eq!("Hello, Alice!", &message);
//! ```
//!
//! [`ICU4X`]: ../icu/index.html
extern crate alloc;
mod impls;
mod ops;
use alloc::string::String;
use core::fmt;
/// A hint to help consumers of Writeable pre-allocate bytes before they call write_to.
///
/// LengthHint implements std::ops::Add and similar traits for easy composition.
///
/// See this issue for more info: <https://github.com/unicode-org/icu4x/issues/370>.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum LengthHint {
/// Default value: no hint is provided.
Undefined,
/// An exact length hint. This value is expected to equal the actual length from write_to.
Exact(usize),
}
impl LengthHint {
/// Returns a recommendation for the number of bytes to pre-allocate.
///
/// # Examples
///
/// ```
/// use writeable::Writeable;
///
/// fn pre_allocate_string(w: &impl Writeable) -> String {
/// String::with_capacity(w.write_len().capacity())
/// }
/// ```
pub fn capacity(&self) -> usize {
match self {
Self::Undefined => 0,
Self::Exact(len) => *len,
}
}
/// Returns whether the LengthHint indicates that the string is exactly 0 bytes long.
pub fn is_zero(&self) -> bool {
match self {
Self::Undefined => false,
Self::Exact(len) => *len == 0,
}
}
}
/// Writeable is an alternative to std::fmt::Display with the addition of a length function.
pub trait Writeable {
/// Writes bytes to the given sink. Errors from the sink are bubbled up.
fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result;
/// Returns a hint for the number of bytes that will be written to the sink.
///
/// Override this method if it can be computed quickly.
fn write_len(&self) -> LengthHint {
LengthHint::Undefined
}
/// Creates a new String with the data from this Writeable. Like ToString,
/// but smaller and faster.
///
/// Not intended to be overriden.
fn writeable_to_string(&self) -> String {
let mut output = String::with_capacity(self.write_len().capacity());
self.write_to(&mut output)
.expect("impl Write for String is infallible");
output
}
}
/// Testing macro for types implementing Writeable. The first argument should be a string, and
/// the second argument should be a `&dyn Writeable`.
///
/// The macro tests for equality of both string content and string length. If your Writeable
/// implementation returns an inexact string length, don't use this macro.
///
/// # Examples
///
/// ```
/// use writeable::Writeable;
/// use writeable::LengthHint;
/// use writeable::assert_writeable_eq;
/// use std::fmt;
///
/// struct Demo;
/// impl Writeable for Demo {
/// fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
/// sink.write_str("foo")
/// }
/// fn write_len(&self) -> LengthHint {
/// LengthHint::Exact(3)
/// }
/// }
///
/// assert_writeable_eq!("foo", &Demo);
/// assert_writeable_eq!("foo", &Demo, "Message: {}", "Hello World");
/// ```
#[macro_export]
macro_rules! assert_writeable_eq {
($expected_str:expr, $actual_writeable:expr $(,)?) => {
{
use $crate::Writeable;
let writeable = $actual_writeable;
assert_eq!($expected_str, writeable.writeable_to_string());
if let $crate::LengthHint::Exact(len) = writeable.write_len() {
assert_eq!($expected_str.len(), len);
}
}
};
($expected_str:expr, $actual_writeable:expr, $($arg:tt)+) => {
{
use $crate::Writeable;
let writeable = $actual_writeable;
assert_eq!($expected_str, writeable.writeable_to_string(), $($arg)+);
if let $crate::LengthHint::Exact(len) = writeable.write_len() {
assert_eq!($expected_str.len(), len, $($arg)+);
}
}
};
}