shared_mime/runtime/
xdg_package.rs

1//! Types for shared-mime definitions parsed from package files.
2//!
3//! This uses quick-xml and Serde to deserialize the XML package definitions
4//! from the [XDG Shared Mime Info database][xdg].
5//!
6//! [xdg]:
7//!     https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
8use serde::Deserialize;
9
10use crate::record::{GlobRule, MimeTypeRecord};
11
12// Shared mime info database.
13#[derive(Deserialize, Debug, Clone)]
14pub struct MimeInfoPackage {
15    /// The MIME types defined in this package.
16    #[serde(rename = "mime-type")]
17    pub types: Vec<MimeType>,
18}
19
20/// Single MIME type record from the database.
21#[derive(Deserialize, Debug, Clone)]
22pub struct MimeType {
23    #[serde(rename = "@type")]
24    pub name: String,
25
26    #[serde(rename = "$value")]
27    pub elements: Vec<MimeTypeElement>,
28}
29
30/// Element in a MIME definition.
31#[derive(Deserialize, Debug, Clone)]
32#[serde(rename_all = "kebab-case")]
33pub enum MimeTypeElement {
34    Comment(CommentElement),
35    Glob(GlobElement),
36    GlobDeleteall,
37    SubClassOf(TypeRefElement),
38    Alias(TypeRefElement),
39    Acronym(String),
40    ExpandedAcronym(String),
41    GenericIcon,
42    Magic,
43    MagicDeleteall,
44    Treemagic,
45    #[serde(rename = "root-XML")]
46    RootXML,
47}
48
49/// Comment (description) from the MIME database.
50#[derive(Deserialize, Debug, Clone)]
51pub struct CommentElement {
52    #[serde(rename = "@lang")]
53    pub lang: Option<String>,
54
55    #[serde(rename = "$text")]
56    pub value: String,
57}
58
59/// Glob element.
60#[derive(Deserialize, Debug, Clone)]
61pub struct GlobElement {
62    #[serde(rename = "@pattern")]
63    pub pattern: String,
64    #[serde(rename = "@weight")]
65    pub weight: Option<i32>,
66    #[serde(rename = "@case-sensitive", default)]
67    pub case_sensitive: bool,
68}
69
70/// Element that references another type.
71#[derive(Deserialize, Debug, Clone)]
72pub struct TypeRefElement {
73    #[serde(rename = "@type")]
74    pub mimetype: String,
75}
76
77impl MimeInfoPackage {
78    pub fn into_records(self) -> Vec<MimeTypeRecord> {
79        self.types.into_iter().map(|m| m.into()).collect()
80    }
81}
82
83impl From<MimeType> for MimeTypeRecord {
84    fn from(mime: MimeType) -> Self {
85        return MimeTypeRecord {
86            name: mime.name,
87            description: mime
88                .elements
89                .iter()
90                .filter_map(|e| match e {
91                    MimeTypeElement::Comment(c) => Some(c),
92                    _ => None,
93                })
94                .find(|c| match &c.lang {
95                    None => true,
96                    Some(lang) if lang == "en" => true,
97                    _ => false,
98                })
99                .map(|c| c.value.clone()),
100            globs: mime
101                .elements
102                .iter()
103                .filter_map(|e| match e {
104                    MimeTypeElement::Glob(g) => Some(g.into()),
105                    _ => None,
106                })
107                .collect(),
108            superclasses: mime
109                .elements
110                .iter()
111                .filter_map(|e| match e {
112                    MimeTypeElement::SubClassOf(tr) => Some(tr.mimetype.clone()),
113                    _ => None,
114                })
115                .collect(),
116            aliases: mime
117                .elements
118                .iter()
119                .filter_map(|e| match e {
120                    MimeTypeElement::Alias(tr) => Some(tr.mimetype.clone()),
121                    _ => None,
122                })
123                .collect(),
124        };
125    }
126}
127
128impl From<GlobElement> for GlobRule {
129    fn from(glob: GlobElement) -> Self {
130        return GlobRule {
131            pattern: glob.pattern,
132            weight: glob.weight.unwrap_or(50),
133            case_sensitive: glob.case_sensitive,
134        };
135    }
136}
137
138impl From<&GlobElement> for GlobRule {
139    fn from(glob: &GlobElement) -> Self {
140        return GlobRule {
141            pattern: glob.pattern.clone(),
142            weight: glob.weight.unwrap_or(50),
143            case_sensitive: glob.case_sensitive,
144        };
145    }
146}