parallel_disk_usage/data_tree/reflection/
par_methods.rs

1use super::{ConversionError, Reflection};
2use crate::{data_tree::DataTree, size};
3use rayon::prelude::*;
4use std::{ffi::OsStr, iter::once};
5
6impl<Name, Size> Reflection<Name, Size>
7where
8    Name: Send,
9    Size: size::Size + Send,
10{
11    /// Attempting to convert a [`Reflection`] into a valid [`DataTree`].
12    pub fn par_try_into_tree(self) -> Result<DataTree<Name, Size>, ConversionError<Name, Size>> {
13        let Reflection {
14            name,
15            size,
16            children,
17        } = self;
18        let excess_child = children
19            .iter()
20            .enumerate()
21            .find(|(_, child)| child.size > size);
22        if let Some((index, _)) = excess_child {
23            let path = once(name).collect();
24            let child = keep_one(children, index).expect("excess child");
25            return Err(ConversionError::ExcessiveChildren { path, size, child });
26        }
27        let children: Result<Vec<_>, _> = children
28            .into_par_iter()
29            .map(Self::par_try_into_tree)
30            .collect();
31        let children = match children {
32            Ok(children) => children,
33            Err(ConversionError::ExcessiveChildren {
34                mut path,
35                size,
36                child,
37            }) => {
38                path.push_front(name);
39                return Err(ConversionError::ExcessiveChildren { path, size, child });
40            }
41        };
42        Ok(DataTree {
43            name,
44            size,
45            children,
46        })
47    }
48
49    /// Attempt to transform names and sizes.
50    pub fn par_try_map<TargetName, TargetSize, Error, Transform>(
51        self,
52        transform: Transform,
53    ) -> Result<Reflection<TargetName, TargetSize>, Error>
54    where
55        TargetName: Send,
56        TargetSize: size::Size + Send + Sync,
57        Error: Send,
58        Transform: Fn(Name, Size) -> Result<(TargetName, TargetSize), Error> + Copy + Sync,
59    {
60        let Reflection {
61            name,
62            size,
63            children,
64        } = self;
65        let children = children
66            .into_par_iter()
67            .map(|child| child.par_try_map(transform))
68            .collect::<Result<Vec<_>, _>>()?;
69        let (name, size) = transform(name, size)?;
70        Ok(Reflection {
71            name,
72            size,
73            children,
74        })
75    }
76
77    /// Attempt to convert all names from `OsString` to `String`.
78    pub fn par_convert_names_to_utf8(self) -> Result<Reflection<String, Size>, Name>
79    where
80        Name: AsRef<OsStr>,
81        Size: Sync,
82    {
83        self.par_try_map(|name, size| {
84            name.as_ref()
85                .to_str()
86                .map(|name| (name.to_string(), size))
87                .ok_or(name)
88        })
89    }
90}
91
92/// Extract an item at `index` if it exists. Then drop all remaining items.
93#[inline]
94fn keep_one<Item>(vec: Vec<Item>, index: usize) -> Option<Item> {
95    // Worry not about performance, for `std::vec::IntoIter::advanced_by` is overridden with O(1) algorithm!
96    vec.into_iter().nth(index)
97}