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};