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