diff --git a/Cargo.lock b/Cargo.lock index fe9549cfc4..daa28f9de2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7132,7 +7132,7 @@ dependencies = [ "restate-clock", "restate-encoding", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "serde_json", "thiserror 2.0.17", @@ -7351,7 +7351,7 @@ dependencies = [ "restate-tracing-instrumentation", "restate-types", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "serde_json", "serde_with", @@ -7391,7 +7391,7 @@ dependencies = [ "restate-types", "restate-wal-protocol", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "thiserror 2.0.17", "tokio", "tracing", @@ -7448,7 +7448,7 @@ dependencies = [ "restate-timer-queue", "restate-types", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "tempfile", "test-log", @@ -7739,7 +7739,7 @@ dependencies = [ "restate-worker", "restate-workspace-hack", "rust-rocksdb", - "schemars 0.8.22", + "schemars 1.2.0", "semver", "serde", "serde_json", @@ -7875,7 +7875,7 @@ dependencies = [ "http-serde", "prost 0.14.1", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "serde_json", "serde_with", @@ -7917,7 +7917,7 @@ dependencies = [ "restate-workspace-hack", "rlimit", "rustls 0.23.35", - "schemars 0.8.22", + "schemars 1.2.0", "serde_json", "tempfile", "test-log", @@ -7961,7 +7961,7 @@ dependencies = [ "restate-workspace-hack", "ring", "rustls 0.23.35", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "serde_json", "serde_with", @@ -8081,7 +8081,7 @@ dependencies = [ "restate-storage-api", "restate-types", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde_json", "thiserror 2.0.17", "tokio", @@ -8110,7 +8110,7 @@ version = "1.6.0-dev" dependencies = [ "jiff", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "serde_json", "serde_with", @@ -8128,7 +8128,7 @@ dependencies = [ "restate-test-util", "restate-types", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "test-log", "tokio", "tokio-util", @@ -8164,7 +8164,7 @@ dependencies = [ "restate-serde-util", "restate-types", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "thiserror 2.0.17", "tokio", "tonic", @@ -8240,7 +8240,7 @@ dependencies = [ "restate-utoipa", "restate-workspace-hack", "rustc-hash", - "schemars 0.8.22", + "schemars 1.2.0", "semver", "serde", "serde_json", @@ -8382,7 +8382,7 @@ dependencies = [ "restate-wal-protocol", "restate-workspace-hack", "rstest", - "schemars 0.8.22", + "schemars 1.2.0", "serde", "strum", "test-log", @@ -8433,14 +8433,11 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "crossterm", - "darling 0.21.3", - "darling_core 0.21.3", "derive_more", "derive_more-impl", "digest", "either", "enum-map", - "enumset", "flate2", "futures-channel", "futures-core", @@ -8862,10 +8859,8 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ - "bytes", "dyn-clone", - "enumset", - "schemars_derive", + "schemars_derive 0.8.22", "serde", "serde_json", ] @@ -8888,8 +8883,10 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ + "bytes", "dyn-clone", "ref-cast", + "schemars_derive 1.2.0", "serde", "serde_json", ] @@ -8906,6 +8903,18 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "schemars_derive" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4908ad288c5035a8eb12cfdf0d49270def0a268ee162b75eeee0f85d155a7c45" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.111", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -11160,7 +11169,7 @@ dependencies = [ "restate-types", "restate-worker", "restate-workspace-hack", - "schemars 0.8.22", + "schemars 1.2.0", "serde_json", "tempfile", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 8a359e91d4..b654084745 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,7 +185,6 @@ object_store = { version = "0.13.0", features = ["aws", "azure", "gcp"] } octocrab = { version = "0.44.1" } opentelemetry = { version = "0.31" } opentelemetry-contrib = { version = "0.23" } -opentelemetry-http = { version = "0.31" } opentelemetry-otlp = { version = "0.31" } opentelemetry-semantic-conventions = { version = "0.31" } opentelemetry_sdk = { version = "0.31" } @@ -201,7 +200,6 @@ prost-dto = { version = "0.0.4" } prost-types = { version = "0.14.1" } quote = "1" rand = "0.9.2" -rangemap = "1.7.1" regex = { version = "1.12" } reqwest = { version = "0.12", default-features = false, features = [ "json", @@ -215,7 +213,7 @@ rocksdb = { version = "0.43.0", package = "rust-rocksdb", features = [ ], git = "https://github.com/restatedev/rust-rocksdb", rev = "de8911652d398e9bfbb6bbc42a7b4f7296f6d101" } rstest = "0.26.1" rustls = { version = "0.23.35", default-features = false, features = ["ring"] } -schemars = { version = "0.8", features = ["bytes", "enumset"] } +schemars = { version = "1.2", features = ["bytes1"] } semver = { version = "1.0", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/crates/serde-util/src/byte_count.rs b/crates/serde-util/src/byte_count.rs index 95b3b1f20f..e832ca6eaf 100644 --- a/crates/serde-util/src/byte_count.rs +++ b/crates/serde-util/src/byte_count.rs @@ -23,32 +23,28 @@ pub type NonZeroByteCount = ByteCount; #[cfg(feature = "schema")] impl schemars::JsonSchema for ByteCount { - fn schema_name() -> String { - "HumanBytes".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + "HumanBytes".into() } fn schema_id() -> std::borrow::Cow<'static, str> { std::borrow::Cow::Owned(std::concat!(std::module_path!(), "::", "HumanBytes").to_owned()) } - fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - schema.format = Some("human-bytes".to_owned()); - let validation = schema.string(); - validation.pattern = Some(r"^\d+(\.\d+)? ?[KMG]B$".to_string()); - validation.min_length = Some(1); - let validation = schema.number(); - validation.minimum = Some(1.0); - let metadata = schema.metadata(); - metadata.title = Some("Human-readable bytes".to_owned()); - metadata.description = Some("Human-readable bytes".to_owned()); - schema.into() + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "pattern": r"^\d+(\.\d+)? ?[KMG]B$", + "minLength": 1, + "title": "Human-readable bytes", + "description": "Human-readable bytes", + }) } } #[cfg(feature = "schema")] impl schemars::JsonSchema for ByteCount { - fn schema_name() -> String { - "NonZeroHumanBytes".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + "NonZeroHumanBytes".into() } fn schema_id() -> std::borrow::Cow<'static, str> { @@ -57,18 +53,14 @@ impl schemars::JsonSchema for ByteCount { ) } - fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - schema.format = Some("non-zero human-bytes".to_owned()); - let validation = schema.string(); - validation.pattern = Some(r"^\d+(\.\d+)? ?[KMG]B$".to_string()); - validation.min_length = Some(1); - let validation = schema.number(); - validation.minimum = Some(1.0); - let metadata = schema.metadata(); - metadata.title = Some("Non-zero human-readable bytes".to_owned()); - metadata.description = Some("Non-zero human-readable bytes".to_owned()); - schema.into() + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "pattern": r"^\d+(\.\d+)? ?[KMG]B$", + "minLength": 1, + "title": "Non-zero human-readable bytes", + "description": "Non-zero human-readable bytes", + }) } } diff --git a/crates/time-util/src/duration.rs b/crates/time-util/src/duration.rs index 231ba56353..40e1d7d5de 100644 --- a/crates/time-util/src/duration.rs +++ b/crates/time-util/src/duration.rs @@ -586,8 +586,8 @@ impl<'de, const CAN_BE_ZERO: bool> serde::de::Deserialize<'de> for Duration String { - "FriendlyDuration".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + "FriendlyDuration".into() } fn schema_id() -> std::borrow::Cow<'static, str> { @@ -596,29 +596,28 @@ impl schemars::JsonSchema for FriendlyDuration { ) } - fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - let validation = schema.string(); - validation.min_length = Some(1); - let metadata = schema.metadata(); - metadata.title = Some("Human-readable duration".to_owned()); - metadata.description = Some("Duration string in either jiff human friendly or ISO8601 format. Check https://docs.rs/jiff/latest/jiff/struct.Span.html#parsing-and-printing for more details.".to_owned()); - metadata.examples = vec![ - serde_json::Value::String("10 hours".to_owned()), - serde_json::Value::String("5 days".to_owned()), - serde_json::Value::String("5d".to_owned()), - serde_json::Value::String("1h 4m".to_owned()), - serde_json::Value::String("P40D".to_owned()), - serde_json::Value::String("0".to_owned()), - ]; - schema.into() + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "minLength": 1, + "title": "Human-readable duration", + "description": "Duration string in either jiff human friendly or ISO8601 format. Check https://docs.rs/jiff/latest/jiff/struct.Span.html#parsing-and-printing for more details.", + "examples": [ + "10 hours", + "5 days", + "5d", + "1h 4m", + "P40D", + "0" + ] + }) } } #[cfg(feature = "schema")] impl schemars::JsonSchema for NonZeroFriendlyDuration { - fn schema_name() -> String { - "NonZeroFriendlyDuration".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + "NonZeroFriendlyDuration".into() } fn schema_id() -> std::borrow::Cow<'static, str> { @@ -627,21 +626,20 @@ impl schemars::JsonSchema for NonZeroFriendlyDuration { ) } - fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - let validation = schema.string(); - validation.min_length = Some(1); - let metadata = schema.metadata(); - metadata.title = Some("Non-zero human-readable duration".to_owned()); - metadata.description = Some("Non-zero duration string in either jiff human friendly or ISO8601 format. Check https://docs.rs/jiff/latest/jiff/struct.Span.html#parsing-and-printing for more details.".to_owned()); - metadata.examples = vec![ - serde_json::Value::String("10 hours".to_owned()), - serde_json::Value::String("5 days".to_owned()), - serde_json::Value::String("5d".to_owned()), - serde_json::Value::String("1h 4m".to_owned()), - serde_json::Value::String("P40D".to_owned()), - ]; - schema.into() + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "minLength": 1, + "title": "Non-zero human-readable duration", + "description": "Non-zero duration string in either jiff human friendly or ISO8601 format. Check https://docs.rs/jiff/latest/jiff/struct.Span.html#parsing-and-printing for more details.", + "examples": [ + "10 hours", + "5 days", + "5d", + "1h 4m", + "P40D", + ] + }) } } diff --git a/crates/types/src/config/common.rs b/crates/types/src/config/common.rs index 4c23b58828..965c2c0141 100644 --- a/crates/types/src/config/common.rs +++ b/crates/types/src/config/common.rs @@ -193,6 +193,10 @@ impl Default for ListenerOptions

{ pub struct CommonOptions { /// Defines the roles which this Restate node should run, by default the node /// starts with all roles. + #[cfg_attr( + feature = "schemars", + schemars(schema_with = "schema::enumset_role_schema") + )] pub roles: EnumSet, /// # Node Name @@ -486,6 +490,16 @@ pub struct CommonOptions { serde_with::with_prefix!(pub prefix_tokio_console "tokio_console_"); +#[cfg(feature = "schemars")] +pub(crate) mod schema { + use super::*; + + pub fn enumset_role_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + // EnumSet serializes as an array of Role values + generator.subschema_for::>() + } +} + impl CommonOptions { pub fn fabric_listener_options(&self) -> &ListenerOptions { &self.fabric_listener_options @@ -862,7 +876,8 @@ impl Default for MetadataClientOptions { feature = "schemars", schemars( title = "Metadata client type", - description = "The metadata client type to store metadata" + description = "The metadata client type to store metadata", + !try_from, ) )] pub enum MetadataClientKind { diff --git a/crates/types/src/identifiers.rs b/crates/types/src/identifiers.rs index 2ef689526b..2024e040b0 100644 --- a/crates/types/src/identifiers.rs +++ b/crates/types/src/identifiers.rs @@ -21,10 +21,11 @@ use bytes::Bytes; use bytestring::ByteString; use generic_array::ArrayLength; use rand::RngCore; -use restate_encoding::{BilrostNewType, NetSerde}; use sha2::{Digest, Sha256}; use ulid::Ulid; +use restate_encoding::{BilrostNewType, NetSerde}; + use crate::base62_util::{base62_encode_fixed_width_u128, base62_max_length_for_type}; use crate::errors::IdDecodeError; use crate::id_util::IdResourceType; @@ -635,11 +636,11 @@ impl FromStr for InvocationId { #[cfg(feature = "schemars")] impl schemars::JsonSchema for InvocationId { - fn schema_name() -> String { + fn schema_name() -> std::borrow::Cow<'static, str> { ::schema_name() } - fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema { ::json_schema(g) } } @@ -771,17 +772,14 @@ impl LambdaARN { #[cfg(feature = "schemars")] impl schemars::JsonSchema for LambdaARN { - fn schema_name() -> String { + fn schema_name() -> std::borrow::Cow<'static, str> { "LambdaARN".into() } - fn json_schema(_: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - instance_type: Some(schemars::schema::InstanceType::String.into()), - format: Some("arn".to_string()), - ..Default::default() - } - .into() + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + }) } } @@ -789,7 +787,7 @@ impl schemars::JsonSchema for LambdaARN { mod utoipa_schema { use crate::identifiers::{InvocationId, LambdaARN}; use std::borrow::Cow; - use utoipa::openapi::{Object, RefOr, Schema, SchemaFormat, Type}; + use utoipa::openapi::{Object, RefOr, Schema, Type}; use utoipa::{PartialSchema, ToSchema}; impl ToSchema for LambdaARN { @@ -800,13 +798,7 @@ mod utoipa_schema { impl PartialSchema for LambdaARN { fn schema() -> RefOr { - Schema::Object( - Object::builder() - .schema_type(Type::String) - .format(Some(SchemaFormat::Custom("arn".to_owned()))) - .build(), - ) - .into() + Schema::Object(Object::builder().schema_type(Type::String).build()).into() } } @@ -1055,11 +1047,11 @@ macro_rules! ulid_backed_id { #[cfg(feature = "schemars")] impl schemars::JsonSchema for [< $res_name Id >] { - fn schema_name() -> String { + fn schema_name() -> std::borrow::Cow<'static, str> { ::schema_name() } - fn json_schema(g: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema { ::json_schema(g) } } diff --git a/crates/types/src/net/address.rs b/crates/types/src/net/address.rs index a343e6c12d..a44743c0de 100644 --- a/crates/types/src/net/address.rs +++ b/crates/types/src/net/address.rs @@ -190,31 +190,27 @@ impl Default for BindAddress

{ #[cfg(feature = "schemars")] impl schemars::JsonSchema for BindAddress

{ - fn schema_name() -> String { - format!("BindAddress-{}", P::NAME) + fn schema_name() -> std::borrow::Cow<'static, str> { + format!("BindAddress-{}", P::NAME).into() } fn schema_id() -> std::borrow::Cow<'static, str> { format!("{}::BindAddress[{}]", std::module_path!(), P::NAME).into() } - fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - schema.format = Some("ip:port".to_owned()); - let metadata = schema.metadata(); - metadata.title = Some("Bind address".to_owned()); - metadata.description = Some(format!( + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "title": "Bind address", + "description": format!( "The local network address to bind on for {}. This service uses default port {} and \ will create a unix-socket file at the data directory under the name `{}`", P::NAME, P::DEFAULT_PORT, P::UDS_NAME - )); - metadata.examples = vec![ - serde_json::Value::String(format!("0.0.0.0:{}", P::DEFAULT_PORT)), - serde_json::Value::String(format!("127.0.0.1:{}", P::DEFAULT_PORT)), - ]; - schema.into() + ), + "examples": [format!("0.0.0.0:{}", P::DEFAULT_PORT), format!("127.0.0.1:{}", P::DEFAULT_PORT)] + }) } } @@ -281,30 +277,26 @@ pub struct AdvertisedAddress { #[cfg(feature = "schemars")] impl schemars::JsonSchema for AdvertisedAddress

{ - fn schema_name() -> String { - format!("AdvertisedAddress-{}", P::NAME) + fn schema_name() -> std::borrow::Cow<'static, str> { + format!("AdvertisedAddress-{}", P::NAME).into() } fn schema_id() -> std::borrow::Cow<'static, str> { format!("{}::AdvertisedAddress[{}]", std::module_path!(), P::NAME).into() } - fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { - let mut schema: schemars::schema::SchemaObject = generator.subschema_for::().into(); - let metadata = schema.metadata(); - metadata.title = Some("advertised address".to_owned()); - metadata.description = Some(format!( + fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema!({ + "type": "string", + "title": "advertised address", + "description": format!( "An externally accessible URI address for {}. This can be set to unix:restate-data/{} \ to advertise the automatically created unix-socket instead of using tcp if needed", P::NAME, P::UDS_NAME - )); - metadata.examples = vec![ - serde_json::Value::String(format!("http//127.0.0.1:{}/", P::DEFAULT_PORT)), - serde_json::Value::String("https://my-host/".to_owned()), - serde_json::Value::String(format!("unix:/data/restate-data/{}", P::UDS_NAME)), - ]; - schema.into() + ), + "examples": [format!("http//127.0.0.1:{}/", P::DEFAULT_PORT), "https://my-host/", format!("unix:/data/restate-data/{}", P::UDS_NAME)] + }) } } diff --git a/deny.toml b/deny.toml index 19f8fbcc28..a347d14522 100644 --- a/deny.toml +++ b/deny.toml @@ -117,9 +117,6 @@ skip = [ # Clash with criterion { name = "itertools" }, - # clash between rdkafka and many other libraries - { name = "indexmap" }, - # clash between prost and otel libraries { name = "prost" }, { name = "prost-derive" }, diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs index 5565ff7e39..3155706719 100644 --- a/tools/xtask/src/main.rs +++ b/tools/xtask/src/main.rs @@ -16,14 +16,13 @@ use std::{env, io}; use anyhow::bail; use reqwest::header::ACCEPT; -use restate_core::partitions::PartitionRouting; -use restate_ingestion_client::IngestionClient; -use restate_types::partitions::state::PartitionReplicaSetStates; -use schemars::r#gen::SchemaSettings; +use schemars::generate::SchemaSettings; use restate_admin::service::AdminService; +use restate_core::partitions::PartitionRouting; use restate_core::{TaskCenter, TaskCenterBuilder, TestCoreEnv}; use restate_core::{TaskCenterFutureExt, TaskKind}; +use restate_ingestion_client::IngestionClient; use restate_service_client::{AssumeRoleCacheMode, ServiceClient}; use restate_service_protocol::discovery::ServiceDiscovery; use restate_storage_query_datafusion::table_docs; @@ -41,6 +40,7 @@ use restate_types::invocation::{ use restate_types::journal_v2::{EntryIndex, Signal}; use restate_types::live::Constant; use restate_types::net::listener::Listeners; +use restate_types::partitions::state::PartitionReplicaSetStates; use restate_types::retries::RetryPolicy; use restate_types::schema::subscriptions::Subscription; use restate_types::state_mut::ExternalStateMutation; @@ -49,7 +49,7 @@ use restate_worker::WorkerHandle; use restate_worker::WorkerHandleError; fn generate_config_schema() -> anyhow::Result<()> { - let schema = SchemaSettings::draft2019_09() + let schema = SchemaSettings::draft2020_12() .into_generator() .into_root_schema_for::(); println!("{}", serde_json::to_string_pretty(&schema)?); diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 9c99f4b560..466976b7c5 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -46,12 +46,9 @@ comfy-table = { version = "7" } criterion = { version = "0.5", features = ["async_tokio"] } crossbeam-epoch = { version = "0.9" } crossbeam-utils = { version = "0.8" } -darling = { version = "0.21" } -darling_core = { version = "0.21", default-features = false, features = ["suggestions"] } digest = { version = "0.10", features = ["mac", "std"] } either = { version = "1" } enum-map = { version = "2", default-features = false, features = ["serde"] } -enumset = { version = "1", default-features = false, features = ["serde"] } flate2 = { version = "1", features = ["zlib-rs"] } futures-channel = { version = "0.3", features = ["sink"] } futures-core = { version = "0.3" } @@ -176,12 +173,9 @@ comfy-table = { version = "7" } criterion = { version = "0.5", features = ["async_tokio"] } crossbeam-epoch = { version = "0.9" } crossbeam-utils = { version = "0.8" } -darling = { version = "0.21" } -darling_core = { version = "0.21", default-features = false, features = ["suggestions"] } digest = { version = "0.10", features = ["mac", "std"] } either = { version = "1" } enum-map = { version = "2", default-features = false, features = ["serde"] } -enumset = { version = "1", default-features = false, features = ["serde"] } flate2 = { version = "1", features = ["zlib-rs"] } futures-channel = { version = "0.3", features = ["sink"] } futures-core = { version = "0.3" }