paralegal_spdg/
utils.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Utility functions and structs

use std::fmt;
use std::fmt::{Display, Formatter, Write};

/// Write all elements from `it` into the formatter `fmt` using `f`, separating
/// them with `sep`
pub fn write_sep<
    E,
    I: IntoIterator<Item = E>,
    F: FnMut(E, &mut fmt::Formatter<'_>) -> fmt::Result,
>(
    fmt: &mut fmt::Formatter<'_>,
    sep: &str,
    it: I,
    mut f: F,
) -> fmt::Result {
    let mut first = true;
    for e in it {
        if first {
            first = false;
        } else {
            fmt.write_str(sep)?;
        }
        f(e, fmt)?;
    }
    Ok(())
}

/// Has a [`Display`] implementation if the elements of the iterator inside have
/// one. This will render them surrounded by `[` brackets and separated by `, `
/// comma and space
#[derive(Clone)]
pub struct DisplayList<I> {
    iter: I,
}

/// Display this iterator as a list
pub fn display_list<I>(iter: I) -> DisplayList<I> {
    DisplayList { iter }
}

impl<E: Display, I: IntoIterator<Item = E> + Clone> Display for DisplayList<I> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_char('[')?;
        write_sep(f, ", ", self.iter.clone(), |e, f| e.fmt(f))?;
        f.write_char(']')
    }
}

pub mod serde_map_via_vec {
    //! Serialize a [`HashMap`] by converting it to a [`Vec`], lifting
    //! restrictions on the types of permissible keys.
    //!
    //! The JSON serializer for [`HashMap`] needs the keys to serialize to a
    //! JSON string object, but sometimes that is not the case. Since the
    //! [`HashMap`] struct only requires its keys be [`Eq`] and [`Hash`] other
    //! non-string values may have been used as key. Unfortunately you can still
    //! use the [`Serialize`] trait on [`HashMap`], even if the keys do not
    //! serialize to strings. Instead a runtime error will be thrown when a
    //! non-string key is encountered.
    //!
    //! This module converts the [`HashMap`] into a [`Vec`] of tuples and
    //! (de)serializes that, which permits arbitrary types to be used for the
    //! keys.
    //!
    //! You are meant to use both [`serialize`] and [`deserialize`], because the
    //! [`Serialize`] and [`Deserialize`] instances of [`HashMap`] do not work
    //! together with these functions.

    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use std::collections::HashMap;

    /// Serialize a [`HashMap`] by first converting to a [`Vec`] of tuples and
    /// then serializing the vector.
    ///
    /// See module level documentation for usage information.
    pub fn serialize<S: Serializer, K: Serialize, V: Serialize>(
        map: &HashMap<K, V>,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        map.iter().collect::<Vec<_>>().serialize(serializer)
    }

    /// Deserialize a [`HashMap`] by first deserializing a [`Vec`] of tuples and
    /// then converting.
    ///
    /// See module level documentation for usage information.
    pub fn deserialize<
        'de,
        D: Deserializer<'de>,
        K: Deserialize<'de> + std::cmp::Eq + std::hash::Hash,
        V: Deserialize<'de>,
    >(
        deserializer: D,
    ) -> Result<HashMap<K, V>, D::Error> {
        Ok(Vec::deserialize(deserializer)?.into_iter().collect())
    }
}

/// A struct with a [`Display`] implementation taht renders a
/// [`std::time::Duration`] in human readable form, similar to the `humantime`
/// crate, but instead of rendering with arbitrary precision it only renders two
/// "significant sections", e.g. "2h 5min" or "2d 20h". The sections are days
/// (d), hours (h), minutes (min), seconds (s), miliseconds (ms), microseconds
/// (μs) and nanoseconds (ns).
pub struct TruncatedHumanTime(std::time::Duration);

impl From<std::time::Duration> for TruncatedHumanTime {
    fn from(value: std::time::Duration) -> Self {
        Self(value)
    }
}

impl std::fmt::Display for TruncatedHumanTime {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        const SECS_PER_MIN: u64 = 60;
        const MINS_PER_H: u64 = 60;
        const H_PER_D: u64 = 24;
        const MILLIS_PER_SEC: u128 = 1000;
        const MICROS_PER_MILLIS: u128 = 1000;
        const NANOS_PER_MICRO: u128 = 1000;
        let secs = self.0.as_secs();
        let mins = secs / SECS_PER_MIN;
        let hs = mins / MINS_PER_H;
        let days = hs / H_PER_D;
        macro_rules! try_two {
            ($larger:expr, $letter1:expr, $smaller:expr, $letter2:expr, $multiplier:expr $(,)?) => {
                if $larger != 0 {
                    let small = $smaller - ($larger * $multiplier);
                    return write!(f, "{}{} {small}{}", $larger, $letter1, $letter2);
                }
            };
        }
        try_two!(days, 'd', hs, 'h', H_PER_D);
        try_two!(hs, 'h', mins, "min", MINS_PER_H);
        try_two!(mins, "min", secs, 's', SECS_PER_MIN);
        try_two!(secs as u128, 's', self.0.as_millis(), "ms", MILLIS_PER_SEC);
        try_two!(
            self.0.as_millis(),
            "ms",
            self.0.as_micros(),
            "μs",
            MICROS_PER_MILLIS,
        );
        try_two!(
            self.0.as_micros(),
            "μs",
            self.0.as_nanos(),
            "ns",
            NANOS_PER_MICRO,
        );
        write!(f, "{}ns", self.0.as_nanos())
    }
}