Skip to main content

snix_store/pathinfoservice/fs/
mod.rs

1use futures::stream::BoxStream;
2use futures::{StreamExt, TryStreamExt};
3use nix_compat::store_path::StorePathRef;
4use snix_castore::fs::RootNodes;
5use snix_castore::{Node, PathComponent};
6use tonic::async_trait;
7
8use super::PathInfoService;
9
10/// Wrapper to satisfy Rust's orphan rules for trait implementations, as
11/// RootNodes is coming from the [snix-castore] crate.
12#[doc(hidden)]
13#[derive(Clone, Debug)]
14pub struct RootNodesWrapper<T>(T);
15
16impl<T> From<T> for RootNodesWrapper<T>
17where
18    T: PathInfoService,
19{
20    fn from(value: T) -> Self {
21        Self(value)
22    }
23}
24
25#[derive(thiserror::Error, Debug)]
26#[error(transparent)]
27pub struct Error(#[from] super::Error);
28
29/// Implements root node lookup for any [PathInfoService]. This represents a flat
30/// directory structure like /nix/store where each entry in the root filesystem
31/// directory corresponds to a CA node.
32#[async_trait]
33impl<T> RootNodes for RootNodesWrapper<T>
34where
35    T: PathInfoService,
36{
37    type Error = Error;
38
39    async fn get_by_basename(&self, name: &PathComponent) -> Result<Option<Node>, Self::Error> {
40        let Ok(store_path) = StorePathRef::from_bytes(name.as_ref()) else {
41            return Ok(None);
42        };
43
44        Ok(self
45            .0
46            .get(*store_path.digest())
47            .await?
48            .map(|path_info| path_info.node))
49    }
50
51    fn list(&self) -> BoxStream<'static, Result<(PathComponent, Node), Self::Error>> {
52        self.0
53            .list()
54            .map_ok(|path_info| {
55                let name = path_info
56                    .store_path
57                    .to_string()
58                    .as_str()
59                    .try_into()
60                    .expect("Snix bug: StorePath must be PathComponent");
61                (name, path_info.node)
62            })
63            .err_into()
64            .boxed()
65    }
66}