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 crate::xml::{XmlDeserialize, XmlSerialize};
11use serde::{
12 Deserialize, Deserializer, Serialize, Serializer,
13 de::{self, Visitor},
14};
15use std::{
16 fmt,
17 io::{Read, Write},
18 marker::PhantomData,
19 str::FromStr,
20};
21pub use types::*;
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> XmlSerialize for Resource<T> {
91 fn serialize<W: Write>(
92 &self,
93 writer: &mut crate::xml::ser::Serializer<W>,
94 ) -> Result<(), String> {
95 let value = if let Some(package) = &self.package {
96 format!("@{}:{}/{}", package, T::resource_type(), self.name)
97 } else {
98 format!("@{}/{}", T::resource_type(), self.name)
99 };
100 writer
101 .write(xml::writer::XmlEvent::characters(&value))
102 .map_err(|error| error.to_string())
103 }
104}
105
106struct ResourceVisitor<T: ResourceType> {
107 phantom: PhantomData<T>,
108}
109
110impl<T: ResourceType> ResourceVisitor<T> {
111 pub fn new() -> Self {
112 ResourceVisitor {
113 phantom: PhantomData,
114 }
115 }
116}
117
118impl<'de, T: ResourceType> Visitor<'de> for ResourceVisitor<T> {
119 type Value = Resource<T>;
120
121 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
122 formatter.write_str(&format!(
123 "an {} resource in format @[package:]{}/resource_name",
124 T::resource_type(),
125 T::resource_type()
126 ))
127 }
128
129 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
130 where
131 E: de::Error,
132 {
133 parse_resource_with_type(v).map_err(E::custom)
134 }
135}
136
137impl<'de, T: ResourceType> Deserialize<'de> for Resource<T> {
138 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
139 where
140 D: Deserializer<'de>,
141 {
142 deserializer.deserialize_string(ResourceVisitor::new())
143 }
144}
145
146impl<T: ResourceType> XmlDeserialize for Resource<T> {
147 fn deserialize<R: Read>(reader: &mut crate::xml::de::Deserializer<R>) -> Result<Self, String> {
148 loop {
149 match reader.next_event()? {
150 xml::reader::XmlEvent::StartElement { .. } => {}
151 xml::reader::XmlEvent::Characters(ref text_content) => {
152 return parse_resource_with_type(text_content);
153 }
154 _ => {
155 break;
156 }
157 }
158 }
159 Err("Unable to parse attribute".to_string())
160 }
161}
162
163fn parse_resource(resource: &str) -> Result<(Option<String>, String, String), String> {
166 if resource.is_empty() {
167 return Err("value of attribute is empty".to_string());
168 };
169 let split_str: Vec<_> = resource.split('/').collect();
170 if split_str.len() != 2 {
171 return Err(
172 "a wrong resource format, expected format @[package:]resource_type/resource_name"
173 .to_string(),
174 );
175 };
176 let first_part = split_str.first().unwrap(); let resource_type = &first_part[1..];
178 let split_type: Vec<_> = resource_type.split(':').collect();
179 let (resource_type, package) = if split_type.len() == 2 {
180 (split_type[1], Some(split_type[0].to_string()))
181 } else {
182 (split_type[0], None)
183 };
184 let resource_name = split_str.get(1).unwrap(); Ok((
186 package,
187 resource_type.to_string(),
188 resource_name.to_string(),
189 ))
190}
191
192fn parse_resource_with_type<T: ResourceType>(resource: &str) -> Result<Resource<T>, String> {
194 let (package, resource_type, resource_name) = parse_resource(resource)?;
195 if resource_type != T::resource_type() {
196 return Err(format!(
197 "a wrong resource type, expected @[package:]{}/{}, found {}",
198 T::resource_type(),
199 resource_name,
200 resource
201 ));
202 };
203 Ok(Resource {
204 name: resource_name,
205 package,
206 phantom: PhantomData,
207 })
208}