about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2024-10-18T12·41+0200
committerclbot <clbot@tvl.fyi>2024-10-18T21·45+0000
commit9c223450199b466c535f2b715ad68f1f295fa7dc (patch)
tree18834efec0cefeb1a6362095e6b2b4e7e094cfe1
parent47efebfc6fcbce028c0f3df5f9d584119e8e8ffe (diff)
refactor(tvix/[ca]store): use auto_impl r/8835
This implements BS, DS, PS for Box'ed or Arc'ed variants of it with less
code, and less potential to accidentially forget to proxy default trait
methods for blanked impls, as fixed in cl/12658.

Change-Id: If2cdbb563a73792038ebe7bff45d6f880214855b
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12661
Tested-by: BuildkiteCI
Autosubmit: flokli <flokli@flokli.de>
Reviewed-by: edef <edef@edef.eu>
-rw-r--r--tvix/Cargo.lock13
-rw-r--r--tvix/Cargo.nix35
-rw-r--r--tvix/build/src/buildservice/from_addr.rs4
-rw-r--r--tvix/build/src/buildservice/oci.rs4
-rw-r--r--tvix/castore/Cargo.toml1
-rw-r--r--tvix/castore/src/blobservice/mod.rs24
-rw-r--r--tvix/castore/src/directoryservice/combinators.rs4
-rw-r--r--tvix/castore/src/directoryservice/mod.rs27
-rw-r--r--tvix/castore/src/fs/fuse/tests.rs4
-rw-r--r--tvix/castore/src/fs/mod.rs16
-rw-r--r--tvix/store/Cargo.toml1
-rw-r--r--tvix/store/src/pathinfoservice/combinators.rs4
-rw-r--r--tvix/store/src/pathinfoservice/fs/mod.rs11
-rw-r--r--tvix/store/src/pathinfoservice/mod.rs24
-rw-r--r--tvix/store/src/pathinfoservice/nix_http.rs10
-rw-r--r--tvix/store/src/pathinfoservice/signing_wrapper.rs2
16 files changed, 85 insertions, 99 deletions
diff --git a/tvix/Cargo.lock b/tvix/Cargo.lock
index c0c6f1f2432b..ae077003b063 100644
--- a/tvix/Cargo.lock
+++ b/tvix/Cargo.lock
@@ -278,6 +278,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
 [[package]]
+name = "auto_impl"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4572,6 +4583,7 @@ dependencies = [
  "async-process",
  "async-stream",
  "async-tempfile",
+ "auto_impl",
  "bigtable_rs",
  "blake3",
  "bstr",
@@ -4765,6 +4777,7 @@ dependencies = [
  "async-compression",
  "async-process",
  "async-stream",
+ "auto_impl",
  "bigtable_rs",
  "blake3",
  "bstr",
diff --git a/tvix/Cargo.nix b/tvix/Cargo.nix
index 7d25ba51ed17..684fdaf5c812 100644
--- a/tvix/Cargo.nix
+++ b/tvix/Cargo.nix
@@ -992,6 +992,33 @@ rec {
           "portable-atomic" = [ "dep:portable-atomic" ];
         };
       };
+      "auto_impl" = rec {
+        crateName = "auto_impl";
+        version = "1.2.0";
+        edition = "2021";
+        sha256 = "0hmfcahj0vrnzq7rayk7r428zp54x9a8awgw6wil753pbvqz71rw";
+        procMacro = true;
+        authors = [
+          "Ashley Mannix <ashleymannix@live.com.au>"
+          "Lukas Kalbertodt <lukas.kalbertodt@gmail.com>"
+        ];
+        dependencies = [
+          {
+            name = "proc-macro2";
+            packageId = "proc-macro2";
+          }
+          {
+            name = "quote";
+            packageId = "quote";
+          }
+          {
+            name = "syn";
+            packageId = "syn 2.0.79";
+            features = [ "full" "visit" "visit-mut" ];
+          }
+        ];
+
+      };
       "autocfg" = rec {
         crateName = "autocfg";
         version = "1.4.0";
@@ -15132,6 +15159,10 @@ rec {
             packageId = "async-tempfile";
           }
           {
+            name = "auto_impl";
+            packageId = "auto_impl";
+          }
+          {
             name = "bigtable_rs";
             packageId = "bigtable_rs";
             optional = true;
@@ -15918,6 +15949,10 @@ rec {
             packageId = "async-stream";
           }
           {
+            name = "auto_impl";
+            packageId = "auto_impl";
+          }
+          {
             name = "bigtable_rs";
             packageId = "bigtable_rs";
             optional = true;
diff --git a/tvix/build/src/buildservice/from_addr.rs b/tvix/build/src/buildservice/from_addr.rs
index 0f4c190c2aca..ba185bb25514 100644
--- a/tvix/build/src/buildservice/from_addr.rs
+++ b/tvix/build/src/buildservice/from_addr.rs
@@ -20,8 +20,8 @@ pub async fn from_addr<BS, DS>(
     directory_service: DS,
 ) -> std::io::Result<Box<dyn BuildService>>
 where
-    BS: AsRef<dyn BlobService> + Send + Sync + Clone + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Sync + Clone + 'static,
+    BS: BlobService + Send + Sync + Clone + 'static,
+    DS: DirectoryService + Send + Sync + Clone + 'static,
 {
     let url = Url::parse(uri)
         .map_err(|e| std::io::Error::other(format!("unable to parse url: {}", e)))?;
diff --git a/tvix/build/src/buildservice/oci.rs b/tvix/build/src/buildservice/oci.rs
index 875e1de447ef..7b88518e924f 100644
--- a/tvix/build/src/buildservice/oci.rs
+++ b/tvix/build/src/buildservice/oci.rs
@@ -91,8 +91,8 @@ impl<BS, DS> OCIBuildService<BS, DS> {
 #[async_trait]
 impl<BS, DS> BuildService for OCIBuildService<BS, DS>
 where
-    BS: AsRef<dyn BlobService> + Send + Sync + Clone + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Sync + Clone + 'static,
+    BS: BlobService + Clone + 'static,
+    DS: DirectoryService + Clone + 'static,
 {
     #[instrument(skip_all, err)]
     async fn do_build(&self, request: BuildRequest) -> std::io::Result<Build> {
diff --git a/tvix/castore/Cargo.toml b/tvix/castore/Cargo.toml
index 0799b471c34f..aa44e2e8ee4b 100644
--- a/tvix/castore/Cargo.toml
+++ b/tvix/castore/Cargo.toml
@@ -52,6 +52,7 @@ vm-memory = { workspace = true, optional = true }
 vmm-sys-util = { workspace = true, optional = true }
 virtio-bindings = { workspace = true, optional = true }
 wu-manber = { workspace = true }
+auto_impl = "1.2.0"
 
 [build-dependencies]
 prost-build = { workspace = true }
diff --git a/tvix/castore/src/blobservice/mod.rs b/tvix/castore/src/blobservice/mod.rs
index 85292722fa7e..efba927b586b 100644
--- a/tvix/castore/src/blobservice/mod.rs
+++ b/tvix/castore/src/blobservice/mod.rs
@@ -1,5 +1,6 @@
 use std::io;
 
+use auto_impl::auto_impl;
 use tonic::async_trait;
 
 use crate::composition::{Registry, ServiceBuilder};
@@ -29,6 +30,7 @@ pub use self::object_store::{ObjectStoreBlobService, ObjectStoreBlobServiceConfi
 /// which will implement a writer interface, and also provides a close funtion,
 /// to finalize a blob and get its digest.
 #[async_trait]
+#[auto_impl(&, &mut, Arc, Box)]
 pub trait BlobService: Send + Sync {
     /// Check if the service has the blob, by its content hash.
     /// On implementations returning chunks, this must also work for chunks.
@@ -60,28 +62,6 @@ pub trait BlobService: Send + Sync {
     }
 }
 
-#[async_trait]
-impl<A> BlobService for A
-where
-    A: AsRef<dyn BlobService> + Send + Sync,
-{
-    async fn has(&self, digest: &B3Digest) -> io::Result<bool> {
-        self.as_ref().has(digest).await
-    }
-
-    async fn open_read(&self, digest: &B3Digest) -> io::Result<Option<Box<dyn BlobReader>>> {
-        self.as_ref().open_read(digest).await
-    }
-
-    async fn open_write(&self) -> Box<dyn BlobWriter> {
-        self.as_ref().open_write().await
-    }
-
-    async fn chunks(&self, digest: &B3Digest) -> io::Result<Option<Vec<ChunkMeta>>> {
-        self.as_ref().chunks(digest).await
-    }
-}
-
 /// A [tokio::io::AsyncWrite] that the user needs to close() afterwards for persist.
 /// On success, it returns the digest of the written blob.
 #[async_trait]
diff --git a/tvix/castore/src/directoryservice/combinators.rs b/tvix/castore/src/directoryservice/combinators.rs
index 84216de92f90..4dfc19540c47 100644
--- a/tvix/castore/src/directoryservice/combinators.rs
+++ b/tvix/castore/src/directoryservice/combinators.rs
@@ -170,8 +170,8 @@ impl ServiceBuilder for CacheConfig {
         context: &CompositionContext,
     ) -> Result<Arc<dyn DirectoryService>, Box<dyn std::error::Error + Send + Sync + 'static>> {
         let (near, far) = futures::join!(
-            context.resolve(self.near.clone()),
-            context.resolve(self.far.clone())
+            context.resolve::<Self::Output>(self.near.clone()),
+            context.resolve::<Self::Output>(self.far.clone())
         );
         Ok(Arc::new(Cache {
             near: near?,
diff --git a/tvix/castore/src/directoryservice/mod.rs b/tvix/castore/src/directoryservice/mod.rs
index 76c7548d425a..b3cb0f4fd67b 100644
--- a/tvix/castore/src/directoryservice/mod.rs
+++ b/tvix/castore/src/directoryservice/mod.rs
@@ -1,6 +1,7 @@
 use crate::composition::{Registry, ServiceBuilder};
 use crate::{B3Digest, Directory, Error};
 
+use auto_impl::auto_impl;
 use futures::stream::BoxStream;
 use tonic::async_trait;
 mod combinators;
@@ -39,6 +40,7 @@ pub use self::bigtable::{BigtableDirectoryService, BigtableParameters};
 /// This is a simple get and put of [Directory], returning their
 /// digest.
 #[async_trait]
+#[auto_impl(&, &mut, Arc, Box)]
 pub trait DirectoryService: Send + Sync {
     /// Looks up a single Directory message by its digest.
     /// The returned Directory message *must* be valid.
@@ -80,31 +82,6 @@ pub trait DirectoryService: Send + Sync {
     fn put_multiple_start(&self) -> Box<dyn DirectoryPutter>;
 }
 
-#[async_trait]
-impl<A> DirectoryService for A
-where
-    A: AsRef<dyn DirectoryService> + Send + Sync,
-{
-    async fn get(&self, digest: &B3Digest) -> Result<Option<Directory>, Error> {
-        self.as_ref().get(digest).await
-    }
-
-    async fn put(&self, directory: Directory) -> Result<B3Digest, Error> {
-        self.as_ref().put(directory).await
-    }
-
-    fn get_recursive(
-        &self,
-        root_directory_digest: &B3Digest,
-    ) -> BoxStream<'static, Result<Directory, Error>> {
-        self.as_ref().get_recursive(root_directory_digest)
-    }
-
-    fn put_multiple_start(&self) -> Box<dyn DirectoryPutter> {
-        self.as_ref().put_multiple_start()
-    }
-}
-
 /// Provides a handle to put a closure of connected [Directory] elements.
 ///
 /// The consumer can periodically call [DirectoryPutter::put], starting from the
diff --git a/tvix/castore/src/fs/fuse/tests.rs b/tvix/castore/src/fs/fuse/tests.rs
index 9e01204d5da7..0d68af090daf 100644
--- a/tvix/castore/src/fs/fuse/tests.rs
+++ b/tvix/castore/src/fs/fuse/tests.rs
@@ -45,8 +45,8 @@ fn do_mount<P: AsRef<Path>, BS, DS>(
     show_xattr: bool,
 ) -> io::Result<FuseDaemon>
 where
-    BS: AsRef<dyn BlobService> + Send + Sync + Clone + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Sync + Clone + 'static,
+    BS: BlobService + Send + Sync + Clone + 'static,
+    DS: DirectoryService + Send + Sync + Clone + 'static,
 {
     let fs = TvixStoreFs::new(
         blob_service,
diff --git a/tvix/castore/src/fs/mod.rs b/tvix/castore/src/fs/mod.rs
index d124c56297ed..58e01355e96d 100644
--- a/tvix/castore/src/fs/mod.rs
+++ b/tvix/castore/src/fs/mod.rs
@@ -121,8 +121,8 @@ pub struct TvixStoreFs<BS, DS, RN> {
 
 impl<BS, DS, RN> TvixStoreFs<BS, DS, RN>
 where
-    BS: AsRef<dyn BlobService> + Clone + Send,
-    DS: AsRef<dyn DirectoryService> + Clone + Send + 'static,
+    BS: BlobService + Clone + Send,
+    DS: DirectoryService + Clone + Send + 'static,
     RN: RootNodes + Clone + 'static,
 {
     pub fn new(
@@ -186,7 +186,7 @@ where
                     .block_on({
                         let directory_service = self.directory_service.clone();
                         let parent_digest = parent_digest.to_owned();
-                        async move { directory_service.as_ref().get(&parent_digest).await }
+                        async move { directory_service.get(&parent_digest).await }
                     })?
                     .ok_or_else(|| {
                         warn!(directory.digest=%parent_digest, "directory not found");
@@ -302,8 +302,8 @@ const XATTR_NAME_BLOB_DIGEST: &[u8] = b"user.tvix.castore.blob.digest";
 
 impl<BS, DS, RN> Layer for TvixStoreFs<BS, DS, RN>
 where
-    BS: AsRef<dyn BlobService> + Clone + Send + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Clone + 'static,
+    BS: BlobService + Clone + Send + 'static,
+    DS: DirectoryService + Send + Clone + 'static,
     RN: RootNodes + Clone + 'static,
 {
     fn root_inode(&self) -> Self::Inode {
@@ -313,8 +313,8 @@ where
 
 impl<BS, DS, RN> FileSystem for TvixStoreFs<BS, DS, RN>
 where
-    BS: AsRef<dyn BlobService> + Clone + Send + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Clone + 'static,
+    BS: BlobService + Clone + Send + 'static,
+    DS: DirectoryService + Send + Clone + 'static,
     RN: RootNodes + Clone + 'static,
 {
     type Handle = u64;
@@ -674,7 +674,7 @@ where
                 match self.tokio_handle.block_on({
                     let blob_service = self.blob_service.clone();
                     let blob_digest = blob_digest.clone();
-                    async move { blob_service.as_ref().open_read(&blob_digest).await }
+                    async move { blob_service.open_read(&blob_digest).await }
                 }) {
                     Ok(None) => {
                         warn!("blob not found");
diff --git a/tvix/store/Cargo.toml b/tvix/store/Cargo.toml
index b913aed3be95..865b1f4f61b9 100644
--- a/tvix/store/Cargo.toml
+++ b/tvix/store/Cargo.toml
@@ -49,6 +49,7 @@ redb = { workspace = true, features = ["logging"] }
 mimalloc = { workspace = true }
 tonic-reflection = { workspace = true, optional = true }
 bigtable_rs = { workspace = true, optional = true }
+auto_impl = "1.2.0"
 
 [build-dependencies]
 prost-build = { workspace = true }
diff --git a/tvix/store/src/pathinfoservice/combinators.rs b/tvix/store/src/pathinfoservice/combinators.rs
index 1f413cf310a2..f386fd52dc3c 100644
--- a/tvix/store/src/pathinfoservice/combinators.rs
+++ b/tvix/store/src/pathinfoservice/combinators.rs
@@ -88,8 +88,8 @@ impl ServiceBuilder for CacheConfig {
         context: &CompositionContext,
     ) -> Result<Arc<dyn PathInfoService>, Box<dyn std::error::Error + Send + Sync + 'static>> {
         let (near, far) = futures::join!(
-            context.resolve(self.near.clone()),
-            context.resolve(self.far.clone())
+            context.resolve::<Self::Output>(self.near.clone()),
+            context.resolve::<Self::Output>(self.far.clone())
         );
         Ok(Arc::new(Cache {
             near: near?,
diff --git a/tvix/store/src/pathinfoservice/fs/mod.rs b/tvix/store/src/pathinfoservice/fs/mod.rs
index d996ec9f6f76..ea30a2f6477c 100644
--- a/tvix/store/src/pathinfoservice/fs/mod.rs
+++ b/tvix/store/src/pathinfoservice/fs/mod.rs
@@ -20,9 +20,9 @@ pub fn make_fs<BS, DS, PS>(
     show_xattr: bool,
 ) -> TvixStoreFs<BS, DS, RootNodesWrapper<PS>>
 where
-    BS: AsRef<dyn BlobService> + Send + Clone + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Clone + 'static,
-    PS: AsRef<dyn PathInfoService> + Send + Sync + Clone + 'static,
+    BS: BlobService + Send + Clone + 'static,
+    DS: DirectoryService + Send + Clone + 'static,
+    PS: PathInfoService + Send + Sync + Clone + 'static,
 {
     TvixStoreFs::new(
         blob_service,
@@ -46,7 +46,7 @@ pub struct RootNodesWrapper<T>(pub(crate) T);
 #[async_trait]
 impl<T> RootNodes for RootNodesWrapper<T>
 where
-    T: AsRef<dyn PathInfoService> + Send + Sync,
+    T: PathInfoService + Send + Sync,
 {
     async fn get_by_basename(&self, name: &PathComponent) -> Result<Option<Node>, Error> {
         let Ok(store_path) = StorePathRef::from_bytes(name.as_ref()) else {
@@ -55,14 +55,13 @@ where
 
         Ok(self
             .0
-            .as_ref()
             .get(*store_path.digest())
             .await?
             .map(|path_info| path_info.node))
     }
 
     fn list(&self) -> BoxStream<Result<(PathComponent, Node), Error>> {
-        Box::pin(self.0.as_ref().list().map(|result| {
+        Box::pin(self.0.list().map(|result| {
             result.map(|path_info| {
                 let basename = path_info.store_path.to_string();
                 (
diff --git a/tvix/store/src/pathinfoservice/mod.rs b/tvix/store/src/pathinfoservice/mod.rs
index a0c48f5cc9d5..d31a1e652e3b 100644
--- a/tvix/store/src/pathinfoservice/mod.rs
+++ b/tvix/store/src/pathinfoservice/mod.rs
@@ -13,6 +13,7 @@ mod fs;
 #[cfg(test)]
 mod tests;
 
+use auto_impl::auto_impl;
 use futures::stream::BoxStream;
 use tonic::async_trait;
 use tvix_castore::composition::{Registry, ServiceBuilder};
@@ -45,6 +46,7 @@ pub use self::fs::make_fs;
 
 /// The base trait all PathInfo services need to implement.
 #[async_trait]
+#[auto_impl(&, &mut, Arc, Box)]
 pub trait PathInfoService: Send + Sync {
     /// Retrieve a PathInfo message by the output digest.
     async fn get(&self, digest: [u8; 20]) -> Result<Option<PathInfo>, Error>;
@@ -69,28 +71,6 @@ pub trait PathInfoService: Send + Sync {
     }
 }
 
-#[async_trait]
-impl<A> PathInfoService for A
-where
-    A: AsRef<dyn PathInfoService> + Send + Sync + 'static,
-{
-    async fn get(&self, digest: [u8; 20]) -> Result<Option<PathInfo>, Error> {
-        self.as_ref().get(digest).await
-    }
-
-    async fn put(&self, path_info: PathInfo) -> Result<PathInfo, Error> {
-        self.as_ref().put(path_info).await
-    }
-
-    fn list(&self) -> BoxStream<'static, Result<PathInfo, Error>> {
-        self.as_ref().list()
-    }
-
-    fn nar_calculation_service(&self) -> Option<Box<dyn NarCalculationService>> {
-        self.as_ref().nar_calculation_service()
-    }
-}
-
 /// Registers the builtin PathInfoService implementations with the registry
 pub(crate) fn register_pathinfo_services(reg: &mut Registry) {
     reg.register::<Box<dyn ServiceBuilder<Output = dyn PathInfoService>>, CachePathInfoServiceConfig>("cache");
diff --git a/tvix/store/src/pathinfoservice/nix_http.rs b/tvix/store/src/pathinfoservice/nix_http.rs
index ed386f0e9d14..29e04aa45867 100644
--- a/tvix/store/src/pathinfoservice/nix_http.rs
+++ b/tvix/store/src/pathinfoservice/nix_http.rs
@@ -66,8 +66,8 @@ impl<BS, DS> NixHTTPPathInfoService<BS, DS> {
 #[async_trait]
 impl<BS, DS> PathInfoService for NixHTTPPathInfoService<BS, DS>
 where
-    BS: AsRef<dyn BlobService> + Send + Sync + Clone + 'static,
-    DS: AsRef<dyn DirectoryService> + Send + Sync + Clone + 'static,
+    BS: BlobService + Send + Sync + Clone + 'static,
+    DS: DirectoryService + Send + Sync + Clone + 'static,
 {
     #[instrument(skip_all, err, fields(path.digest=nixbase32::encode(&digest)))]
     async fn get(&self, digest: [u8; 20]) -> Result<Option<PathInfo>, Error> {
@@ -316,10 +316,10 @@ impl ServiceBuilder for NixHTTPPathInfoServiceConfig {
         &'a self,
         _instance_name: &str,
         context: &CompositionContext,
-    ) -> Result<Arc<dyn PathInfoService>, Box<dyn std::error::Error + Send + Sync + 'static>> {
+    ) -> Result<Arc<Self::Output>, Box<dyn std::error::Error + Send + Sync + 'static>> {
         let (blob_service, directory_service) = futures::join!(
-            context.resolve(self.blob_service.clone()),
-            context.resolve(self.directory_service.clone())
+            context.resolve::<dyn BlobService>(self.blob_service.clone()),
+            context.resolve::<dyn DirectoryService>(self.directory_service.clone())
         );
         let mut svc = NixHTTPPathInfoService::new(
             Url::parse(&self.base_url)?,
diff --git a/tvix/store/src/pathinfoservice/signing_wrapper.rs b/tvix/store/src/pathinfoservice/signing_wrapper.rs
index 4dff23722888..5898a5baa463 100644
--- a/tvix/store/src/pathinfoservice/signing_wrapper.rs
+++ b/tvix/store/src/pathinfoservice/signing_wrapper.rs
@@ -96,7 +96,7 @@ impl ServiceBuilder for KeyFileSigningPathInfoServiceConfig {
         _instance_name: &str,
         context: &CompositionContext,
     ) -> Result<Arc<dyn PathInfoService>, Box<dyn std::error::Error + Send + Sync + 'static>> {
-        let inner = context.resolve(self.inner.clone()).await?;
+        let inner = context.resolve::<Self::Output>(self.inner.clone()).await?;
         let signing_key = Arc::new(
             parse_keypair(tokio::fs::read_to_string(&self.keyfile).await?.trim())
                 .map_err(|e| Error::StorageError(e.to_string()))?