Module composition

Source
Expand description

The composition module allows composing different kinds of services based on a set of service configurations at runtime.

Store configs are deserialized with serde. The registry provides a stateful mapping from the type tag of an internally tagged enum on the serde side to a Config struct which is deserialized and then returned as a Box<dyn ServiceBuilder<Output = dyn BlobService>> (the same for DirectoryService instead of BlobService etc).

§Example 1.: Implementing a new BlobService

You need a Config struct which implements DeserializeOwned and ServiceBuilder<Output = dyn BlobService>. Provide the user with a function to call with their registry. You register your new type as:

use std::sync::Arc;

use snix_castore::composition::*;
use snix_castore::blobservice::BlobService;

#[derive(serde::Deserialize)]
struct MyBlobServiceConfig {
}

#[tonic::async_trait]
impl ServiceBuilder for MyBlobServiceConfig {
    type Output = dyn BlobService;
    async fn build(&self, _: &str, _: &CompositionContext) -> Result<Arc<Self::Output>, Box<dyn std::error::Error + Send + Sync + 'static>> {
        todo!()
    }
}

impl TryFrom<url::Url> for MyBlobServiceConfig {
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn try_from(url: url::Url) -> Result<Self, Self::Error> {
        todo!()
    }
}

pub fn add_my_service(reg: &mut Registry) {
    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobService>>, MyBlobServiceConfig>("myblobservicetype");
}

Now, when a user deserializes a store config with the type tag “myblobservicetype” into a Box<dyn ServiceBuilder<Output = Arc<dyn BlobService>>>, it will be done via MyBlobServiceConfig.

§Example 2.: Composing stores to get one store

use std::sync::Arc;
use snix_castore::composition::*;
use snix_castore::blobservice::BlobService;

let blob_services_configs_json = serde_json::json!({
  "blobstore1": {
    "type": "memory"
  },
  "blobstore2": {
    "type": "memory"
  },
  "root": {
    "type": "combined",
    "near": "blobstore1",
    "far": "blobstore2"
  }
});

let blob_services_configs = with_registry(&REG, || serde_json::from_value(blob_services_configs_json))?;
let mut blob_service_composition = Composition::new(&REG);
blob_service_composition.extend_with_configs::<dyn BlobService>(blob_services_configs);
let blob_service: Arc<dyn BlobService> = blob_service_composition.build("root").await?;

§Example 3.: Creating another registry extending the default registry with third-party types

let mut my_registry = snix_castore::composition::Registry::default();
snix_castore::composition::add_default_services(&mut my_registry);
add_my_service(&mut my_registry);

Continue with Example 2, with my_registry instead of REG

EXPERIMENTAL: If the xp-composition-url-refs feature is enabled, entrypoints can also be URL strings, which are created as anonymous stores. Instantiations of the same URL will result in a new, distinct anonymous store each time, so creating two memory:// stores with this method will not share the same view. This behavior might change in the future.

Structs§

Composition
CompositionContext
DeserializeWithRegistry
Wrapper type which implements Deserialize using the registry
Registry
Resolves tag names to the corresponding Config type.
RegistryEntry
RegistryWithFakeType 🔒

Enums§

CompositionError
InstantiationState 🔒
TryFromUrlError 🔒

Constants§

ACTIVE_REG 🔒
The active Registry is global state, because there is no convenient and universal way to pass state into the functions usually used for deserialization, e.g. serde_json::from_str, toml::from_str, serde_qs::from_str.

Statics§

REG
The provided registry of snix_castore, with all builtin BlobStore/DirectoryStore implementations

Traits§

ServiceBuilder
This is the trait usually implemented on a per-store-type Config struct and used to instantiate it.

Functions§

add_default_services
Register the builtin services of snix_castore (blob services and directory services) with the given registry. This can be used outside to create your own registry with the builtin types and extra third party types.
with_registry
Run the provided closure with a registry context. Any serde deserialize calls within the closure will use the registry to resolve tag names to the corresponding Config type.

Type Aliases§

FromUrlSeed