webpack_stats/
common.rs

1/*
2 * Copyright [2022] [Kevin Velasco]
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17pub mod chunk;
18pub mod entry;
19pub mod import;
20pub mod module;
21
22use serde::de::{Error, SeqAccess, Visitor};
23use serde::{Deserialize, Deserializer};
24use std::borrow::Cow;
25use std::fmt::{Debug, Display, Formatter};
26use std::marker::PhantomData;
27use std::ops::Add;
28
29/// Represents a duration in miliseconds
30#[derive(Debug, Default)]
31pub struct DurationMillis(std::time::Duration);
32
33impl<'de> Deserialize<'de> for DurationMillis {
34    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35    where
36        D: Deserializer<'de>,
37    {
38        let miliseconds = u64::deserialize(deserializer)?;
39        Ok(Self(std::time::Duration::from_millis(miliseconds)))
40    }
41}
42
43/// Represents a size in bytes.
44#[derive(Default, Deserialize, Copy, Clone, PartialOrd, PartialEq)]
45#[repr(transparent)]
46pub struct SizeBytes(pub f32);
47
48impl Display for SizeBytes {
49    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50        if self.0 > (1024.0 * 1024.0 * 1024.0) {
51            write!(f, "{} GiB", self.0 / (1024.0 * 1024.0 * 1024.0))
52        } else if self.0 > (1024.0 * 1024.0) {
53            write!(f, "{} MiB", self.0 / (1024.0 * 1024.0))
54        } else if self.0 > 1024.0 {
55            write!(f, "{} KiB", self.0 / 1024.0)
56        } else {
57            write!(f, "{} B", self.0)
58        }
59    }
60}
61
62impl Debug for SizeBytes {
63    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64        Display::fmt(&self, f)
65    }
66}
67
68impl Add for SizeBytes {
69    type Output = SizeBytes;
70
71    fn add(self, rhs: Self) -> Self::Output {
72        Self(self.0 + rhs.0)
73    }
74}
75
76/// Abstracts over json values that can be a string or a list of strings
77/// When possible, will store values as a &'de str when deserializing
78pub enum Strings<'a, I>
79where
80    I: ?Sized + ToOwned,
81{
82    Str(Cow<'a, I>),
83    Strs(Vec<Cow<'a, I>>),
84}
85
86impl<'a, I> IntoIterator for Strings<'a, I>
87where
88    I: ?Sized + ToOwned,
89{
90    type Item = Cow<'a, I>;
91    type IntoIter = <Vec<Cow<'a, I>> as IntoIterator>::IntoIter;
92
93    fn into_iter(self) -> Self::IntoIter {
94        match self {
95            Strings::Str(v) => vec![v].into_iter(),
96            Strings::Strs(v) => v.into_iter(),
97        }
98    }
99}
100
101impl<'a, I> Debug for Strings<'a, I>
102where
103    I: ?Sized + ToOwned + Debug,
104    Cow<'a, I>: Debug,
105{
106    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107        match self {
108            Strings::Str(v) => Debug::fmt(v, f),
109            Strings::Strs(v) => Debug::fmt(v, f),
110        }
111    }
112}
113
114impl<I> Default for Strings<'_, I>
115where
116    I: ToOwned + ?Sized,
117    <I as ToOwned>::Owned: Default,
118{
119    fn default() -> Self {
120        Self::Str(Cow::default())
121    }
122}
123
124impl<'de, 'a> Deserialize<'de> for Strings<'a, str>
125where
126    'de: 'a,
127{
128    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129    where
130        D: Deserializer<'de>,
131    {
132        struct Visit<'a>(PhantomData<&'a str>);
133
134        impl<'v> Visitor<'v> for Visit<'v> {
135            type Value = Strings<'v, str>;
136
137            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
138                formatter.write_str("a List<str> or an str")
139            }
140
141            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
142            where
143                E: Error,
144            {
145                Ok(Self::Value::Str(Cow::Owned(v.to_owned())))
146            }
147
148            fn visit_borrowed_str<E>(self, v: &'v str) -> Result<Self::Value, E>
149            where
150                E: Error,
151            {
152                Ok(Self::Value::Str(Cow::Borrowed(v)))
153            }
154
155            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
156            where
157                A: SeqAccess<'v>,
158            {
159                let mut value = vec![];
160                loop {
161                    let next = seq.next_element()?;
162                    match next {
163                        Some(v) => {
164                            value.push(v);
165                        }
166                        None => {
167                            break;
168                        }
169                    }
170                }
171
172                Ok(Self::Value::Strs(value))
173            }
174        }
175
176        deserializer.deserialize_any(Visit(PhantomData))
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use crate::common::Strings;
183    use serde::Deserialize;
184
185    #[test]
186    fn item_or_n_items() {
187        let json_str = r#"
188          {
189            "key": "value\"",
190            "k": ["s", "v"]
191          }
192        "#;
193        #[derive(Deserialize, Debug)]
194        struct Test<'a> {
195            #[serde(borrow)]
196            key: Strings<'a, str>,
197            k: Strings<'a, str>,
198        }
199
200        let value: Test<'_> = serde_json::from_str(json_str).unwrap();
201
202        assert_eq!(value.key.into_iter().count(), 1);
203        assert_eq!(value.k.into_iter().count(), 2);
204    }
205}