android_manifest/resources/
mod.rs1mod any;
2mod mipmap_or_drawable;
3mod res_or_string;
4mod types;
5
6pub use any::*;
7pub use mipmap_or_drawable::*;
8pub use res_or_string::*;
9
10use serde::{
11 Deserialize, Deserializer, Serialize, Serializer,
12 de::{self, Visitor},
13};
14use std::{
15 fmt,
16 io::{Read, Write},
17 marker::PhantomData,
18 str::FromStr,
19};
20pub use types::*;
21use yaserde::{YaDeserialize, YaSerialize};
22
23pub trait ResourceType: FromStr {
25 fn new(name: &str, package: Option<String>) -> Resource<Self> {
27 Resource {
28 name: name.to_string(),
29 package,
30 phantom: PhantomData,
31 }
32 }
33 fn resource_type() -> &'static str;
35}
36
37#[derive(Debug, PartialEq, Eq, Clone)]
39pub struct Resource<T: ResourceType> {
40 name: String,
41 package: Option<String>,
42 phantom: PhantomData<T>,
43}
44
45impl<T: ResourceType> Resource<T> {
46 pub fn new(name: &str) -> Self {
47 Self {
48 name: name.to_string(),
49 package: None,
50 phantom: PhantomData,
51 }
52 }
53
54 pub fn new_with_package(name: &str, package: Option<String>) -> Self {
55 Self {
56 name: name.to_string(),
57 package,
58 phantom: PhantomData,
59 }
60 }
61
62 pub fn name(&self) -> &str {
63 &self.name
64 }
65
66 pub fn resource_type(&self) -> &'static str {
67 T::resource_type()
68 }
69}
70
71impl<T: ResourceType> fmt::Display for Resource<T> {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 if let Some(package) = &self.package {
74 write!(f, "@{}:{}/{}", package, T::resource_type(), self.name)
75 } else {
76 write!(f, "@{}/{}", T::resource_type(), self.name)
77 }
78 }
79}
80
81impl<T: ResourceType> Serialize for Resource<T> {
82 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83 where
84 S: Serializer,
85 {
86 serializer.serialize_str(&self.to_string())
87 }
88}
89
90impl<T: ResourceType> YaSerialize for Resource<T> {
91 fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>) -> Result<(), String> {
92 if let Some(package) = &self.package {
93 let _ret = writer.write(xml::writer::XmlEvent::characters(&format!(
94 "@{}:{}/{}",
95 package,
96 T::resource_type(),
97 self.name
98 )));
99 } else {
100 let _ret = writer.write(xml::writer::XmlEvent::characters(&format!(
101 "@{}/{}",
102 T::resource_type(),
103 self.name
104 )));
105 }
106 Ok(())
107 }
108
109 fn serialize_attributes(
110 &self,
111 attributes: Vec<xml::attribute::OwnedAttribute>,
112 namespace: xml::namespace::Namespace,
113 ) -> Result<
114 (
115 Vec<xml::attribute::OwnedAttribute>,
116 xml::namespace::Namespace,
117 ),
118 String,
119 > {
120 Ok((attributes, namespace))
121 }
122}
123
124struct ResourceVisitor<T: ResourceType> {
125 phantom: PhantomData<T>,
126}
127
128impl<T: ResourceType> ResourceVisitor<T> {
129 pub fn new() -> Self {
130 ResourceVisitor {
131 phantom: PhantomData,
132 }
133 }
134}
135
136impl<'de, T: ResourceType> Visitor<'de> for ResourceVisitor<T> {
137 type Value = Resource<T>;
138
139 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
140 formatter.write_str(&format!(
141 "an {} resource in format @[package:]{}/resource_name",
142 T::resource_type(),
143 T::resource_type()
144 ))
145 }
146
147 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
148 where
149 E: de::Error,
150 {
151 parse_resource_with_type(v).map_err(E::custom)
152 }
153}
154
155impl<'de, T: ResourceType> Deserialize<'de> for Resource<T> {
156 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157 where
158 D: Deserializer<'de>,
159 {
160 deserializer.deserialize_string(ResourceVisitor::new())
161 }
162}
163
164impl<T: ResourceType> YaDeserialize for Resource<T> {
165 fn deserialize<R: Read>(reader: &mut yaserde::de::Deserializer<R>) -> Result<Self, String> {
166 loop {
167 match reader.next_event()? {
168 xml::reader::XmlEvent::StartElement { .. } => {}
169 xml::reader::XmlEvent::Characters(ref text_content) => {
170 return parse_resource_with_type(text_content);
171 }
172 _ => {
173 break;
174 }
175 }
176 }
177 Err("Unable to parse attribute".to_string())
178 }
179}
180
181fn parse_resource(resource: &str) -> Result<(Option<String>, String, String), String> {
184 if resource.is_empty() {
185 return Err("value of attribute is empty".to_string());
186 };
187 let split_str: Vec<_> = resource.split('/').collect();
188 if split_str.len() != 2 {
189 return Err(
190 "a wrong resource format, expected format @[package:]resource_type/resource_name"
191 .to_string(),
192 );
193 };
194 let first_part = split_str.first().unwrap(); let resource_type = &first_part[1..];
196 let split_type: Vec<_> = resource_type.split(':').collect();
197 let (resource_type, package) = if split_type.len() == 2 {
198 (split_type[1], Some(split_type[0].to_string()))
199 } else {
200 (split_type[0], None)
201 };
202 let resource_name = split_str.get(1).unwrap(); Ok((
204 package,
205 resource_type.to_string(),
206 resource_name.to_string(),
207 ))
208}
209
210fn parse_resource_with_type<T: ResourceType>(resource: &str) -> Result<Resource<T>, String> {
212 let (package, resource_type, resource_name) = parse_resource(resource)?;
213 if resource_type != T::resource_type() {
214 return Err(format!(
215 "a wrong resource type, expected @[package:]{}/{}, found {}",
216 T::resource_type(),
217 resource_name,
218 resource
219 ));
220 };
221 Ok(Resource {
222 name: resource_name,
223 package,
224 phantom: PhantomData,
225 })
226}