Skip to main content

eure_document/
proxy.rs

1//! Proxy types for use with `#[eure(via = "...")]` attribute.
2
3extern crate alloc;
4
5use alloc::borrow::{Cow, ToOwned};
6
7use crate::document::constructor::DocumentConstructor;
8use crate::parse::{FromEure, ParseContext, ParseError};
9use crate::write::{IntoEure, WriteError};
10
11/// A proxy type that enables borrowing from the document when parsing `Cow<'doc, T>`.
12///
13/// Unlike the default `Cow<'static, T>` implementation which always returns `Cow::Owned`,
14/// this proxy returns `Cow::Borrowed` by parsing `&'doc T` directly from the document.
15///
16/// # Example
17/// ```ignore
18/// use eure_macros::FromEure;
19/// use std::borrow::Cow;
20///
21/// #[derive(FromEure)]
22/// struct Data<'doc> {
23///     #[eure(via = "eure_document::proxy::BorrowedCow")]
24///     name: Cow<'doc, str>,
25/// }
26/// ```
27pub struct BorrowedCow;
28
29impl<'doc, T> FromEure<'doc, Cow<'doc, T>> for BorrowedCow
30where
31    T: ToOwned + ?Sized,
32    for<'a> &'a T: FromEure<'a>,
33    for<'a> <&'a T as FromEure<'a>>::Error: Into<ParseError>,
34{
35    type Error = ParseError;
36
37    fn parse(ctx: &ParseContext<'doc>) -> Result<Cow<'doc, T>, Self::Error> {
38        ctx.parse::<&'doc T>()
39            .map(Cow::Borrowed)
40            .map_err(Into::into)
41    }
42}
43
44impl<'a, T> IntoEure<Cow<'a, T>> for BorrowedCow
45where
46    T: ToOwned + ?Sized,
47    T::Owned: IntoEure,
48{
49    fn write(value: Cow<'a, T>, c: &mut DocumentConstructor) -> Result<(), WriteError> {
50        <T::Owned as IntoEure>::write(value.into_owned(), c)
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::document::node::NodeValue;
58    use crate::eure;
59    use crate::text::Text;
60    use crate::value::PrimitiveValue;
61
62    #[test]
63    fn test_borrowed_cow_str_from_eure() {
64        let doc = eure!({ name = "hello" });
65        let root_id = doc.get_root_id();
66        let rec = doc.parse_record(root_id).unwrap();
67        let value: Cow<'_, str> = rec.parse_field_with("name", BorrowedCow::parse).unwrap();
68        assert!(matches!(value, Cow::Borrowed(_)));
69        assert_eq!(value, "hello");
70    }
71
72    #[test]
73    fn test_borrowed_cow_str_into_eure() {
74        let mut c = DocumentConstructor::new();
75        let value: Cow<'_, str> = Cow::Borrowed("hello");
76        BorrowedCow::write(value, &mut c).unwrap();
77        let doc = c.finish();
78        assert_eq!(
79            doc.root().content,
80            NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
81        );
82    }
83}