Skip to main content

android_manifest/resources/
res_or_string.rs

1use super::{Resource, ResourceType, ResourceVisitor, StringResource, parse_resource_with_type};
2use crate::xml::{XmlDeserialize, XmlSerialize};
3use serde::{
4    Deserialize, Deserializer, Serialize, Serializer,
5    de::{self, Visitor},
6};
7use std::fmt;
8use std::io::{Read, Write};
9
10/// Enum used when the value can be string resource or just a row string.
11#[derive(Debug, PartialEq, Eq, Clone)]
12pub enum StringResourceOrString {
13    StringResource(Resource<StringResource>),
14    String(String),
15}
16
17impl StringResourceOrString {
18    pub fn resource(name: &str, package: Option<String>) -> StringResourceOrString {
19        Self::StringResource(StringResource::new(name, package))
20    }
21
22    pub fn string(s: &str) -> StringResourceOrString {
23        Self::String(s.to_string())
24    }
25}
26
27impl fmt::Display for StringResourceOrString {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match self {
30            Self::StringResource(r) => write!(f, "{}", r),
31            Self::String(v) => write!(f, "{}", v),
32        }
33    }
34}
35
36impl Serialize for StringResourceOrString {
37    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38    where
39        S: Serializer,
40    {
41        match self {
42            StringResourceOrString::StringResource(resource) => {
43                Serialize::serialize(&resource, serializer)
44            }
45            StringResourceOrString::String(value) => serializer.serialize_str(value),
46        }
47    }
48}
49
50impl XmlSerialize for StringResourceOrString {
51    fn serialize<W: Write>(
52        &self,
53        writer: &mut crate::xml::ser::Serializer<W>,
54    ) -> Result<(), String> {
55        match self {
56            StringResourceOrString::StringResource(resource) => {
57                XmlSerialize::serialize(resource, writer)?;
58            }
59            StringResourceOrString::String(value) => {
60                writer
61                    .write(xml::writer::XmlEvent::characters(value))
62                    .map_err(|error| error.to_string())?;
63            }
64        }
65        Ok(())
66    }
67}
68
69struct StringResourceOrStringVisitor;
70
71impl<'de> Visitor<'de> for StringResourceOrStringVisitor {
72    type Value = StringResourceOrString;
73
74    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
75        formatter.write_str("an string resource in format @string/resource_name or string")
76    }
77
78    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
79    where
80        E: de::Error,
81    {
82        if v.is_empty() {
83            return Err(E::custom("value of attribute is empty"));
84        };
85        if v.starts_with('@') {
86            Ok(StringResourceOrString::StringResource(
87                ResourceVisitor::<StringResource>::new().visit_str(v)?,
88            ))
89        } else {
90            Ok(StringResourceOrString::String(v.to_owned()))
91        }
92    }
93}
94
95impl<'de> Deserialize<'de> for StringResourceOrString {
96    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
97    where
98        D: Deserializer<'de>,
99    {
100        deserializer.deserialize_string(StringResourceOrStringVisitor)
101    }
102}
103
104impl XmlDeserialize for StringResourceOrString {
105    fn deserialize<R: Read>(reader: &mut crate::xml::de::Deserializer<R>) -> Result<Self, String> {
106        loop {
107            match reader.next_event()? {
108                xml::reader::XmlEvent::StartElement { .. } => {}
109                xml::reader::XmlEvent::Characters(text_content) => {
110                    if text_content.is_empty() {
111                        return Err("value of attribute is empty".to_string());
112                    };
113                    if text_content.starts_with('@') {
114                        return Ok(StringResourceOrString::StringResource(
115                            parse_resource_with_type(&text_content)?,
116                        ));
117                    } else {
118                        return Ok(StringResourceOrString::String(text_content));
119                    }
120                }
121                _ => {
122                    break;
123                }
124            }
125        }
126        Err("Unable to parse attribute".to_string())
127    }
128}