diff --git a/Cargo.lock b/Cargo.lock index 08375967ef..bf74245225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3132,7 +3132,7 @@ dependencies = [ "tracing", "tracing-subscriber", "url", - "utoipa", + "utoipa 3.5.0", "utoipa-swagger-ui", ] @@ -5674,8 +5674,8 @@ dependencies = [ "hyper 1.6.0", "hyper-util", "protobuf", - "pyth-lazer-protocol 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pyth-lazer-publisher-sdk 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pyth-lazer-protocol 0.20.0", + "pyth-lazer-publisher-sdk 0.20.0", "reqwest 0.12.23", "serde", "serde_json", @@ -5694,7 +5694,7 @@ dependencies = [ [[package]] name = "pyth-lazer-client" -version = "8.6.0" +version = "8.6.1" dependencies = [ "alloy-primitives 0.8.25", "anyhow", @@ -5712,7 +5712,7 @@ dependencies = [ "hex", "humantime-serde", "libsecp256k1 0.7.2", - "pyth-lazer-protocol 0.20.0", + "pyth-lazer-protocol 0.20.1", "reqwest 0.12.23", "serde", "serde_json", @@ -5727,22 +5727,17 @@ dependencies = [ [[package]] name = "pyth-lazer-protocol" version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efd998c309b88c9f9790addb962cb20cb2528f3c1fe305160f998403306ba7d" dependencies = [ - "alloy-primitives 0.8.25", "anyhow", - "assert_float_eq", - "bincode 1.3.3", - "bs58", "byteorder", "chrono", "derive_more 1.0.0", - "ed25519-dalek 2.1.1", "hex", "humantime", "humantime-serde", "itertools 0.13.0", - "libsecp256k1 0.7.2", - "mry", "protobuf", "rust_decimal", "serde", @@ -5752,28 +5747,36 @@ dependencies = [ [[package]] name = "pyth-lazer-protocol" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efd998c309b88c9f9790addb962cb20cb2528f3c1fe305160f998403306ba7d" +version = "0.20.1" dependencies = [ + "alloy-primitives 0.8.25", "anyhow", + "assert_float_eq", + "bincode 1.3.3", + "bs58", "byteorder", "chrono", "derive_more 1.0.0", + "ed25519-dalek 2.1.1", "hex", "humantime", "humantime-serde", "itertools 0.13.0", + "libsecp256k1 0.7.2", + "mry", "protobuf", "rust_decimal", "serde", "serde_json", "thiserror 2.0.12", + "utoipa 5.4.0", ] [[package]] name = "pyth-lazer-publisher-sdk" version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "988c6a2d6bc8d065a492d49915e803912b263e57ad5e300dc45c5a5471d609c8" dependencies = [ "anyhow", "fs-err", @@ -5785,15 +5788,13 @@ dependencies = [ [[package]] name = "pyth-lazer-publisher-sdk" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "988c6a2d6bc8d065a492d49915e803912b263e57ad5e300dc45c5a5471d609c8" +version = "0.20.1" dependencies = [ "anyhow", "fs-err", "protobuf", "protobuf-codegen", - "pyth-lazer-protocol 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pyth-lazer-protocol 0.20.1", "serde_json", ] @@ -10554,7 +10555,19 @@ dependencies = [ "indexmap 2.10.0", "serde", "serde_json", - "utoipa-gen", + "utoipa-gen 3.5.0", +] + +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap 2.10.0", + "serde", + "serde_json", + "utoipa-gen 5.4.0", ] [[package]] @@ -10570,6 +10583,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "utoipa-swagger-ui" version = "3.1.5" @@ -10582,7 +10606,7 @@ dependencies = [ "rust-embed", "serde", "serde_json", - "utoipa", + "utoipa 3.5.0", "zip", ] diff --git a/lazer/publisher_sdk/rust/Cargo.toml b/lazer/publisher_sdk/rust/Cargo.toml index 08e08ed01c..1928a22bf0 100644 --- a/lazer/publisher_sdk/rust/Cargo.toml +++ b/lazer/publisher_sdk/rust/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "pyth-lazer-publisher-sdk" -version = "0.20.0" +version = "0.20.1" edition = "2021" description = "Pyth Lazer Publisher SDK types." license = "Apache-2.0" repository = "https://github.com/pyth-network/pyth-crosschain" [dependencies] -pyth-lazer-protocol = { version = "0.20.0", path = "../../sdk/rust/protocol" } +pyth-lazer-protocol = { version = "0.20.1", path = "../../sdk/rust/protocol" } anyhow = "1.0.98" protobuf = "3.7.2" serde_json = "1.0.140" diff --git a/lazer/sdk/rust/client/Cargo.toml b/lazer/sdk/rust/client/Cargo.toml index 4573081ee0..cbf2d1b198 100644 --- a/lazer/sdk/rust/client/Cargo.toml +++ b/lazer/sdk/rust/client/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "pyth-lazer-client" -version = "8.6.0" +version = "8.6.1" edition = "2021" description = "A Rust client for Pyth Lazer" license = "Apache-2.0" [dependencies] -pyth-lazer-protocol = { path = "../protocol", version = "0.20.0" } +pyth-lazer-protocol = { path = "../protocol", version = "0.20.1" } tokio = { version = "1", features = ["full"] } tokio-tungstenite = { version = "0.20", features = ["native-tls"] } futures-util = "0.3" diff --git a/lazer/sdk/rust/protocol/Cargo.toml b/lazer/sdk/rust/protocol/Cargo.toml index 1f2999f139..0005dadc0d 100644 --- a/lazer/sdk/rust/protocol/Cargo.toml +++ b/lazer/sdk/rust/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyth-lazer-protocol" -version = "0.20.0" +version = "0.20.1" edition = "2021" description = "Pyth Lazer SDK - protocol types." license = "Apache-2.0" @@ -21,6 +21,7 @@ chrono = "0.4.41" humantime = "2.2.0" hex = "0.4.3" thiserror = "2.0.12" +utoipa = "5.3.1" [dev-dependencies] bincode = "1.3.3" diff --git a/lazer/sdk/rust/protocol/src/api.rs b/lazer/sdk/rust/protocol/src/api.rs index 2f10d3c376..12f995227c 100644 --- a/lazer/sdk/rust/protocol/src/api.rs +++ b/lazer/sdk/rust/protocol/src/api.rs @@ -7,6 +7,7 @@ use std::{ use derive_more::derive::From; use itertools::Itertools as _; use serde::{de::Error, Deserialize, Serialize}; +use utoipa::ToSchema; use crate::{ payload::AggregatedPriceFeedData, @@ -14,11 +15,13 @@ use crate::{ ChannelId, Price, PriceFeedId, PriceFeedProperty, Rate, }; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct LatestPriceRequestRepr { // Either price feed ids or symbols must be specified. + #[schema(example = json!([1]))] pub price_feed_ids: Option>, + #[schema(example = schema_default_symbols)] pub symbols: Option>, pub properties: Vec, // "chains" was renamed to "formats". "chains" is still supported for compatibility. @@ -33,7 +36,7 @@ pub struct LatestPriceRequestRepr { pub channel: Channel, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct LatestPriceRequest(LatestPriceRequestRepr); @@ -79,12 +82,13 @@ impl DerefMut for LatestPriceRequest { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PriceRequestRepr { pub timestamp: TimestampUs, // Either price feed ids or symbols must be specified. pub price_feed_ids: Option>, + #[schema(default)] pub symbols: Option>, pub properties: Vec, pub formats: Vec, @@ -97,7 +101,7 @@ pub struct PriceRequestRepr { pub channel: Channel, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PriceRequest(PriceRequestRepr); @@ -143,7 +147,7 @@ impl DerefMut for PriceRequest { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct ReducePriceRequest { pub payload: JsonUpdate, @@ -158,7 +162,14 @@ pub fn default_parsed() -> bool { true } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +pub fn schema_default_symbols() -> Option> { + None +} +pub fn schema_default_price_feed_ids() -> Option> { + Some(vec![PriceFeedId(1)]) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub enum DeliveryFormat { /// Deliver stream updates as JSON text messages. @@ -168,7 +179,7 @@ pub enum DeliveryFormat { Binary, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub enum Format { Evm, @@ -177,7 +188,7 @@ pub enum Format { LeUnsigned, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub enum JsonBinaryEncoding { #[default] @@ -185,9 +196,11 @@ pub enum JsonBinaryEncoding { Hex, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, From)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, From, ToSchema)] +#[schema(example = "fixed_rate@200ms")] pub enum Channel { FixedRate(FixedRate), + #[schema(rename = "real_time")] RealTime, } @@ -275,11 +288,12 @@ impl<'de> Deserialize<'de> for Channel { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscriptionParamsRepr { // Either price feed ids or symbols must be specified. pub price_feed_ids: Option>, + #[schema(default)] pub symbols: Option>, pub properties: Vec, // "chains" was renamed to "formats". "chains" is still supported for compatibility. @@ -299,7 +313,7 @@ pub struct SubscriptionParamsRepr { pub ignore_invalid_feeds: bool, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscriptionParams(SubscriptionParamsRepr); @@ -345,14 +359,14 @@ impl DerefMut for SubscriptionParams { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct JsonBinaryData { pub encoding: JsonBinaryEncoding, pub data: String, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct JsonUpdate { /// Present unless `parsed = false` is specified in subscription params. @@ -372,7 +386,7 @@ pub struct JsonUpdate { pub le_unsigned: Option, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct ParsedPayload { #[serde(with = "crate::serde_str::timestamp")] @@ -380,7 +394,7 @@ pub struct ParsedPayload { pub price_feeds: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct ParsedFeedPayload { pub price_feed_id: PriceFeedId, @@ -491,7 +505,7 @@ impl ParsedFeedPayload { } /// A request sent from the client to the server. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(tag = "type")] #[serde(rename_all = "camelCase")] pub enum WsRequest { @@ -499,10 +513,12 @@ pub enum WsRequest { Unsubscribe(UnsubscribeRequest), } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] pub struct SubscriptionId(pub u64); -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscribeRequest { pub subscription_id: SubscriptionId, @@ -510,14 +526,14 @@ pub struct SubscribeRequest { pub params: SubscriptionParams, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct UnsubscribeRequest { pub subscription_id: SubscriptionId, } /// A JSON response sent from the server to the client. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, From)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, From, ToSchema)] #[serde(tag = "type")] #[serde(rename_all = "camelCase")] pub enum WsResponse { @@ -530,13 +546,13 @@ pub enum WsResponse { } /// Sent from the server after a successul subscription. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscribedResponse { pub subscription_id: SubscriptionId, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct InvalidFeedSubscriptionDetails { pub unknown_ids: Vec, @@ -545,7 +561,7 @@ pub struct InvalidFeedSubscriptionDetails { pub unstable: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscribedWithInvalidFeedIdsIgnoredResponse { pub subscription_id: SubscriptionId, @@ -553,7 +569,7 @@ pub struct SubscribedWithInvalidFeedIdsIgnoredResponse { pub ignored_invalid_feed_ids: InvalidFeedSubscriptionDetails, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct UnsubscribedResponse { pub subscription_id: SubscriptionId, @@ -561,7 +577,7 @@ pub struct UnsubscribedResponse { /// Sent from the server if the requested subscription or unsubscription request /// could not be fulfilled. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct SubscriptionErrorResponse { pub subscription_id: SubscriptionId, @@ -570,7 +586,7 @@ pub struct SubscriptionErrorResponse { /// Sent from the server if an internal error occured while serving data for an existing subscription, /// or a client request sent a bad request. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct ErrorResponse { pub error: String, @@ -578,7 +594,7 @@ pub struct ErrorResponse { /// Sent from the server when new data is available for an existing subscription /// (only if `delivery_format == Json`). -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct StreamUpdatedResponse { pub subscription_id: SubscriptionId, diff --git a/lazer/sdk/rust/protocol/src/lib.rs b/lazer/sdk/rust/protocol/src/lib.rs index ff6f16da8f..fc580b44ef 100644 --- a/lazer/sdk/rust/protocol/src/lib.rs +++ b/lazer/sdk/rust/protocol/src/lib.rs @@ -24,6 +24,7 @@ pub mod time; use derive_more::derive::{From, Into}; use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; pub use crate::{ dynamic_value::DynamicValue, @@ -39,8 +40,21 @@ pub use crate::{ pub struct PublisherId(pub u16); #[derive( - Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, From, Into, + Debug, + Clone, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Serialize, + Deserialize, + From, + Into, + ToSchema, )] +#[schema(value_type = u32)] pub struct PriceFeedId(pub u32); #[derive( @@ -55,7 +69,7 @@ impl ChannelId { pub const FIXED_RATE_1000: ChannelId = ChannelId(4); } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub enum PriceFeedProperty { Price, diff --git a/lazer/sdk/rust/protocol/src/price.rs b/lazer/sdk/rust/protocol/src/price.rs index 9bd706dc90..d95ab1547c 100644 --- a/lazer/sdk/rust/protocol/src/price.rs +++ b/lazer/sdk/rust/protocol/src/price.rs @@ -7,6 +7,7 @@ use { serde::{Deserialize, Serialize}, std::num::NonZeroI64, thiserror::Error, + utoipa::ToSchema, }; #[derive(Debug, Error)] @@ -21,8 +22,11 @@ pub enum PriceError { Overflow, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] #[repr(transparent)] +#[schema(value_type = i64)] pub struct Price(NonZeroI64); impl Price { diff --git a/lazer/sdk/rust/protocol/src/rate.rs b/lazer/sdk/rust/protocol/src/rate.rs index 7c76de26b4..3f5113b173 100644 --- a/lazer/sdk/rust/protocol/src/rate.rs +++ b/lazer/sdk/rust/protocol/src/rate.rs @@ -6,6 +6,7 @@ use { rust_decimal::{prelude::FromPrimitive, Decimal}, serde::{Deserialize, Serialize}, thiserror::Error, + utoipa::ToSchema, }; #[derive(Debug, Error)] @@ -18,8 +19,11 @@ pub enum RateError { Overflow, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] #[repr(transparent)] +#[schema(value_type = i64)] pub struct Rate(i64); impl Rate { diff --git a/lazer/sdk/rust/protocol/src/time.rs b/lazer/sdk/rust/protocol/src/time.rs index 5f34a53c3c..eb6cfcde7b 100644 --- a/lazer/sdk/rust/protocol/src/time.rs +++ b/lazer/sdk/rust/protocol/src/time.rs @@ -11,11 +11,15 @@ use { }, serde::{Deserialize, Serialize}, std::time::{Duration, SystemTime}, + utoipa::ToSchema, }; /// Unix timestamp with microsecond resolution. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] #[repr(transparent)] +#[schema(value_type = u64)] pub struct TimestampUs(u64); #[cfg_attr(feature = "mry", mry::mry)] @@ -279,7 +283,10 @@ impl TryFrom for chrono::DateTime { } /// Non-negative duration with microsecond resolution. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] +#[schema(value_type = u64)] pub struct DurationUs(u64); impl DurationUs { @@ -487,7 +494,8 @@ pub mod duration_us_serde_humantime { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, ToSchema)] +#[schema(as = String, example = "fixed_rate@200ms")] pub struct FixedRate { rate: DurationUs, }