oxiplate_traits/
cow_str.rs1extern crate alloc;
2
3use alloc::borrow::Cow;
4use alloc::fmt;
5use alloc::string::ToString;
6
7use crate::{Escaper, FastEscape};
8
9#[diagnostic::on_unimplemented(
21 message = "{Self} is expected to be prefixed by `>` and implement \
22 `::oxiplate_traits::ToCowString`.",
23 label = "Insert `>` prefix before this expression if `{Self}` is a string-like value (`str`, \
24 `impl Display`, etc).",
25 note = "Consider implementing `::oxiplate_traits::ToCowStr` if `{Self}` is owned by your \
26 crate, and then prefix with `>`.",
27 note = "If `{Self}` is not a string-like value, perhaps you meant to pass a different \
28 argument to the filter?",
29 note = "Oxiplate efficiently builds `::std::borrow::Cow<'a, str>` when a `>` prefix is used \
30 on an expression, and wraps it in `::oxiplate_traits::CowStr<'a>` which is used by \
31 filters for string arguments. Because the syntax for doing so is not obvious and \
32 prone to silently breaking, this alternative syntax is used to let Oxiplate handle \
33 the details while ensuring it's tested properly."
34)]
35pub trait CowStr<'a> {
36 #[must_use]
40 fn cow_str(self) -> Cow<'a, str>;
41}
42
43pub struct CowStrWrapper<'a>(Cow<'a, str>);
47
48impl<'a> CowStrWrapper<'a> {
49 #[must_use]
51 #[inline]
52 pub fn new(cow_str: Cow<'a, str>) -> Self {
53 Self(cow_str)
54 }
55}
56
57impl<'a> CowStr<'a> for CowStrWrapper<'a> {
58 #[inline]
59 fn cow_str(self) -> Cow<'a, str> {
60 self.0
61 }
62}
63
64impl<'a, W: fmt::Write + ?Sized> FastEscape<'a, W> for CowStrWrapper<'a> {
65 #[inline]
66 fn oxiplate_fast_escape(&'a self, f: &mut W, escaper: &impl Escaper) -> fmt::Result {
67 #[cfg(feature = "debug-fast-escape-type-priority")]
68 f.write_str("CowStrWrapper(")?;
69
70 escaper.escape(f, self.0.as_ref())?;
71
72 #[cfg(feature = "debug-fast-escape-type-priority")]
73 f.write_str(")")?;
74
75 Ok(())
76 }
77
78 #[inline]
79 fn oxiplate_fast_raw(&'a self, f: &mut W) -> fmt::Result {
80 #[cfg(feature = "debug-fast-escape-type-priority")]
81 f.write_str("CowStrWrapper(")?;
82
83 f.write_str(self.0.as_ref())?;
84
85 #[cfg(feature = "debug-fast-escape-type-priority")]
86 f.write_str(")")?;
87
88 Ok(())
89 }
90}
91
92pub struct ToCowStrWrapper<'a, T>(&'a T);
108
109impl<'a, T> ToCowStrWrapper<'a, T> {
110 #[inline]
112 pub fn new(value: &'a T) -> Self {
113 Self(value)
114 }
115}
116
117pub trait ToCowStr<'a> {
121 fn to_cow_str(&'a self) -> Cow<'a, str>;
124}
125
126impl<'a, T: FastCowStr<'a>> ToCowStr<'a> for &ToCowStrWrapper<'a, T> {
127 #[inline]
128 fn to_cow_str(&'a self) -> Cow<'a, str> {
129 self.0.oxiplate_cow_str()
130 }
131}
132
133impl<'a, T: ToString> ToCowStr<'a> for &&ToCowStrWrapper<'a, T> {
134 #[inline]
135 fn to_cow_str(&'a self) -> Cow<'a, str> {
136 Cow::Owned(self.0.to_string())
137 }
138}
139
140pub trait FastCowStr<'a> {
142 fn oxiplate_cow_str(&'a self) -> Cow<'a, str>;
145}
146
147impl<'a> FastCowStr<'a> for &'a str {
148 #[inline]
149 fn oxiplate_cow_str(&'a self) -> Cow<'a, str> {
150 Cow::Borrowed(self)
151 }
152}