Skip to main content

procss/
utils.rs

1// ┌───────────────────────────────────────────────────────────────────────────┐
2// │                                                                           │
3// │  ██████╗ ██████╗  ██████╗   Copyright (C) 2022, The Prospective Company   │
4// │  ██╔══██╗██╔══██╗██╔═══██╗                                                │
5// │  ██████╔╝██████╔╝██║   ██║  This file is part of the Procss library,      │
6// │  ██╔═══╝ ██╔══██╗██║   ██║  distributed under the terms of the            │
7// │  ██║     ██║  ██║╚██████╔╝  Apache License 2.0.  The full license can     │
8// │  ╚═╝     ╚═╝  ╚═╝ ╚═════╝   be found in the LICENSE file.                 │
9// │                                                                           │
10// └───────────────────────────────────────────────────────────────────────────┘
11
12use crate::render::RenderCss;
13
14/// A wrapper around [`Vec`] which guarantees at least `N` elements.
15#[derive(Clone, Debug, Eq, PartialEq, Hash)]
16pub struct MinVec<T, const N: usize>([T; N], Vec<T>);
17
18impl<T, const N: usize> MinVec<T, N>
19where
20    T: std::fmt::Debug,
21{
22    /// Create a new N-element-guaranteed collection.
23    pub fn new(head: [T; N], tail: Vec<T>) -> Self {
24        MinVec(head, tail)
25    }
26
27    /// Iterate over the values in this collection.
28    pub fn iter(&self) -> impl Iterator<Item = &'_ T> {
29        self.0.iter().chain(self.1.iter())
30    }
31
32    /// Iterate over the values in this collection.
33    pub fn iter_mut(&mut self) -> impl Iterator<Item = &'_ mut T> {
34        self.0.iter_mut().chain(self.1.iter_mut())
35    }
36}
37
38impl<T: RenderCss, const N: usize> RenderCss for MinVec<T, N> {
39    fn render(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        for x in self.0.iter() {
41            x.render(f)?;
42        }
43
44        for x in self.1.iter() {
45            write!(f, ",")?;
46            x.render(f)?;
47        }
48
49        Ok(())
50    }
51}
52
53/// Givens a root path `outdir` and a relative path `path`, remove the extension
54/// to the latter and join with the former.  If the latter path is not relative,
55/// return the former.  Useful for moving directory trees while retaining their
56/// relative structure to some root.
57pub fn join_paths(outdir: &Path, path: &Path) -> PathBuf {
58    if let Some(parent) = path.parent() {
59        PathBuf::from(outdir).join(parent)
60    } else {
61        PathBuf::from(outdir)
62    }
63}
64
65#[cfg(feature = "iotest")]
66mod mock {
67    #[mockall::automock]
68    pub trait IoTestFs {
69        fn read_to_string(path: &std::path::Path) -> std::io::Result<String>;
70        // where
71        //     P: AsRef<std::path::Path> + 'static;
72
73        fn read(path: &std::path::Path) -> std::io::Result<Vec<u8>>;
74
75        fn create_dir_all<P>(path: P) -> std::io::Result<()>
76        where
77            P: AsRef<std::path::Path> + 'static;
78
79        fn write<P, C>(path: P, content: C) -> std::io::Result<()>
80        where
81            P: AsRef<std::path::Path> + 'static,
82            C: AsRef<[u8]> + 'static;
83    }
84}
85
86#[cfg(not(feature = "iotest"))]
87pub use std::fs;
88use std::path::{Path, PathBuf};
89
90#[cfg(feature = "iotest")]
91pub use mock::{IoTestFs, MockIoTestFs as fs};