Skip to main content

android_manifest/resources/
mipmap_or_drawable.rs

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