android_manifest/resources/
res_or_string.rs1use 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#[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}