cargo fmt

This commit is contained in:
Vincent Stuyck 2026-03-01 16:39:54 +01:00
parent 357b81db80
commit f8a336429a
3 changed files with 140 additions and 84 deletions

View File

@ -25,7 +25,7 @@ pub enum DomainType {
ActivationRun, ActivationRun,
Ruleset, Ruleset,
Rule, Rule,
Dict Dict,
} }
impl fmt::Display for DomainType { impl fmt::Display for DomainType {

View File

@ -1,14 +1,16 @@
use std::fmt::Display; use std::fmt::Display;
use serde::{Deserialize, Serialize};
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::api::{DomainExtension, DomainObject, domain_bulk_read, domain_client, domain_create, domain_delete, domain_update}; use crate::api::{
DomainExtension, DomainObject, domain_bulk_read, domain_client, domain_create, domain_delete,
domain_update,
};
use crate::{ApiClient, Client, Error, Result}; use crate::{ApiClient, Client, Error, Result};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct Ruleset { pub struct Ruleset {
@ -26,7 +28,7 @@ pub struct Ruleset {
// item_enum: Option<()>, // item_enum: Option<()>,
// this value is not set when searching for a specific ruleset (dont ask me why) // this value is not set when searching for a specific ruleset (dont ask me why)
pub match_type: Option<MatchType>, pub match_type: Option<MatchType>,
pub number_of_rules: usize pub number_of_rules: usize,
} }
impl DomainExtension for Ruleset { impl DomainExtension for Ruleset {
@ -41,7 +43,7 @@ pub enum MatchType {
First, First,
Dict, Dict,
List, List,
Varies Varies,
} }
domain_client!(Ruleset, ruleset_api); domain_client!(Ruleset, ruleset_api);
@ -98,15 +100,13 @@ impl RulesetQuery {
} }
} }
impl ApiClient<Ruleset> { impl ApiClient<Ruleset> {
pub async fn read(&self, id: impl Display) -> Result<Ruleset> { pub async fn read(&self, id: impl Display) -> Result<Ruleset> {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct RulesetCompact { struct RulesetCompact {
name: String, name: String,
folder: Option<String>, folder: Option<String>,
number_of_rules: usize number_of_rules: usize,
} }
impl DomainExtension for RulesetCompact { impl DomainExtension for RulesetCompact {
@ -124,7 +124,6 @@ impl ApiClient<Ruleset> {
item_type: None, item_type: None,
item_name: None, item_name: None,
match_type: None, match_type: None,
} }
} }
} }
@ -141,16 +140,16 @@ domain_bulk_read!(Ruleset, RulesetQuery);
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct Rule { pub struct Rule {
#[serde(default, skip_serializing_if="Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub folder_index: Option<usize>, pub folder_index: Option<usize>,
#[serde(default, skip_serializing_if="Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<Uuid>, pub id: Option<Uuid>,
pub ruleset: String, pub ruleset: String,
pub folder: String, pub folder: String,
pub properties: RuleProperties, pub properties: RuleProperties,
pub value_raw: String, pub value_raw: String,
pub conditions: RuleCondition pub conditions: RuleCondition,
} }
impl DomainExtension for Rule { impl DomainExtension for Rule {
@ -213,7 +212,7 @@ pub struct RuleProperties {
pub description: String, pub description: String,
pub comment: String, pub comment: String,
pub documentation_url: String, pub documentation_url: String,
pub disabled: bool pub disabled: bool,
} }
impl RuleProperties { impl RuleProperties {
@ -275,7 +274,10 @@ pub struct RuleCondition {
impl RuleCondition { impl RuleCondition {
/// Match hosts whose name is one of the given values. /// Match hosts whose name is one of the given values.
pub fn match_hosts(&mut self, hosts: Vec<String>) { pub fn match_hosts(&mut self, hosts: Vec<String>) {
self.host_name = Some(MatchCondition { match_on: hosts, operator: MatchOperator::OneOf }); self.host_name = Some(MatchCondition {
match_on: hosts,
operator: MatchOperator::OneOf,
});
} }
pub fn matching_hosts(mut self, hosts: Vec<String>) -> Self { pub fn matching_hosts(mut self, hosts: Vec<String>) -> Self {
self.match_hosts(hosts); self.match_hosts(hosts);
@ -284,7 +286,10 @@ impl RuleCondition {
/// Exclude hosts whose name is one of the given values. /// Exclude hosts whose name is one of the given values.
pub fn exclude_hosts(&mut self, hosts: Vec<String>) { pub fn exclude_hosts(&mut self, hosts: Vec<String>) {
self.host_name = Some(MatchCondition { match_on: hosts, operator: MatchOperator::NoneOf }); self.host_name = Some(MatchCondition {
match_on: hosts,
operator: MatchOperator::NoneOf,
});
} }
pub fn excluding_hosts(mut self, hosts: Vec<String>) -> Self { pub fn excluding_hosts(mut self, hosts: Vec<String>) -> Self {
self.exclude_hosts(hosts); self.exclude_hosts(hosts);
@ -298,7 +303,10 @@ impl RuleCondition {
/// Match services whose description is one of the given values. /// Match services whose description is one of the given values.
pub fn match_services(&mut self, services: Vec<String>) { pub fn match_services(&mut self, services: Vec<String>) {
self.service_description = Some(MatchCondition { match_on: services, operator: MatchOperator::OneOf }); self.service_description = Some(MatchCondition {
match_on: services,
operator: MatchOperator::OneOf,
});
} }
pub fn matching_services(mut self, services: Vec<String>) -> Self { pub fn matching_services(mut self, services: Vec<String>) -> Self {
self.match_services(services); self.match_services(services);
@ -307,7 +315,10 @@ impl RuleCondition {
/// Exclude services whose description is one of the given values. /// Exclude services whose description is one of the given values.
pub fn exclude_services(&mut self, services: Vec<String>) { pub fn exclude_services(&mut self, services: Vec<String>) {
self.service_description = Some(MatchCondition { match_on: services, operator: MatchOperator::NoneOf }); self.service_description = Some(MatchCondition {
match_on: services,
operator: MatchOperator::NoneOf,
});
} }
pub fn excluding_services(mut self, services: Vec<String>) -> Self { pub fn excluding_services(mut self, services: Vec<String>) -> Self {
self.exclude_services(services); self.exclude_services(services);
@ -321,7 +332,10 @@ impl RuleCondition {
/// Require the host tag `key` to equal `value`. /// Require the host tag `key` to equal `value`.
pub fn require_host_tag(&mut self, key: String, value: String) { pub fn require_host_tag(&mut self, key: String, value: String) {
self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::Is(value) }); self.host_tags.push(HostTagCondition {
key,
match_on: TagMatchOperator::Is(value),
});
} }
pub fn with_host_tag(mut self, key: String, value: String) -> Self { pub fn with_host_tag(mut self, key: String, value: String) -> Self {
self.require_host_tag(key, value); self.require_host_tag(key, value);
@ -330,7 +344,10 @@ impl RuleCondition {
/// Require the host tag `key` to not equal `value`. /// Require the host tag `key` to not equal `value`.
pub fn exclude_host_tag(&mut self, key: String, value: String) { pub fn exclude_host_tag(&mut self, key: String, value: String) {
self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::IsNot(value) }); self.host_tags.push(HostTagCondition {
key,
match_on: TagMatchOperator::IsNot(value),
});
} }
pub fn without_host_tag(mut self, key: String, value: String) -> Self { pub fn without_host_tag(mut self, key: String, value: String) -> Self {
self.exclude_host_tag(key, value); self.exclude_host_tag(key, value);
@ -339,7 +356,10 @@ impl RuleCondition {
/// Require the host tag `key` to be one of `values`. /// Require the host tag `key` to be one of `values`.
pub fn require_any_host_tag(&mut self, key: String, values: Vec<String>) { pub fn require_any_host_tag(&mut self, key: String, values: Vec<String>) {
self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::OneOff(values) }); self.host_tags.push(HostTagCondition {
key,
match_on: TagMatchOperator::OneOff(values),
});
} }
pub fn with_any_host_tag(mut self, key: String, values: Vec<String>) -> Self { pub fn with_any_host_tag(mut self, key: String, values: Vec<String>) -> Self {
self.require_any_host_tag(key, values); self.require_any_host_tag(key, values);
@ -348,7 +368,10 @@ impl RuleCondition {
/// Require the host tag `key` to be none of `values`. /// Require the host tag `key` to be none of `values`.
pub fn exclude_any_host_tag(&mut self, key: String, values: Vec<String>) { pub fn exclude_any_host_tag(&mut self, key: String, values: Vec<String>) {
self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::NoneOff(values) }); self.host_tags.push(HostTagCondition {
key,
match_on: TagMatchOperator::NoneOff(values),
});
} }
pub fn without_any_host_tag(mut self, key: String, values: Vec<String>) -> Self { pub fn without_any_host_tag(mut self, key: String, values: Vec<String>) -> Self {
self.exclude_any_host_tag(key, values); self.exclude_any_host_tag(key, values);
@ -357,7 +380,10 @@ impl RuleCondition {
/// Add a host label group that must ALL match (AND). /// Add a host label group that must ALL match (AND).
pub fn require_host_labels(&mut self, labels: Vec<LabelCondition>) { pub fn require_host_labels(&mut self, labels: Vec<LabelCondition>) {
self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::And, label_group: labels }); self.host_label_groups.push(LabelGroupCondition {
operator: LabelOperator::And,
label_group: labels,
});
} }
pub fn with_host_labels(mut self, labels: Vec<LabelCondition>) -> Self { pub fn with_host_labels(mut self, labels: Vec<LabelCondition>) -> Self {
self.require_host_labels(labels); self.require_host_labels(labels);
@ -366,7 +392,10 @@ impl RuleCondition {
/// Add a host label group where ANY must match (OR). /// Add a host label group where ANY must match (OR).
pub fn require_any_host_label(&mut self, labels: Vec<LabelCondition>) { pub fn require_any_host_label(&mut self, labels: Vec<LabelCondition>) {
self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::Or, label_group: labels }); self.host_label_groups.push(LabelGroupCondition {
operator: LabelOperator::Or,
label_group: labels,
});
} }
pub fn with_any_host_label(mut self, labels: Vec<LabelCondition>) -> Self { pub fn with_any_host_label(mut self, labels: Vec<LabelCondition>) -> Self {
self.require_any_host_label(labels); self.require_any_host_label(labels);
@ -375,7 +404,10 @@ impl RuleCondition {
/// Add a host label group that must NOT match (NOT). /// Add a host label group that must NOT match (NOT).
pub fn exclude_host_labels(&mut self, labels: Vec<LabelCondition>) { pub fn exclude_host_labels(&mut self, labels: Vec<LabelCondition>) {
self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::Not, label_group: labels }); self.host_label_groups.push(LabelGroupCondition {
operator: LabelOperator::Not,
label_group: labels,
});
} }
pub fn excluding_host_labels(mut self, labels: Vec<LabelCondition>) -> Self { pub fn excluding_host_labels(mut self, labels: Vec<LabelCondition>) -> Self {
self.exclude_host_labels(labels); self.exclude_host_labels(labels);
@ -384,7 +416,10 @@ impl RuleCondition {
/// Add a service label group that must ALL match (AND). /// Add a service label group that must ALL match (AND).
pub fn require_service_labels(&mut self, labels: Vec<LabelCondition>) { pub fn require_service_labels(&mut self, labels: Vec<LabelCondition>) {
self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::And, label_group: labels }); self.service_label_groups.push(LabelGroupCondition {
operator: LabelOperator::And,
label_group: labels,
});
} }
pub fn with_service_labels(mut self, labels: Vec<LabelCondition>) -> Self { pub fn with_service_labels(mut self, labels: Vec<LabelCondition>) -> Self {
self.require_service_labels(labels); self.require_service_labels(labels);
@ -393,7 +428,10 @@ impl RuleCondition {
/// Add a service label group where ANY must match (OR). /// Add a service label group where ANY must match (OR).
pub fn require_any_service_label(&mut self, labels: Vec<LabelCondition>) { pub fn require_any_service_label(&mut self, labels: Vec<LabelCondition>) {
self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::Or, label_group: labels }); self.service_label_groups.push(LabelGroupCondition {
operator: LabelOperator::Or,
label_group: labels,
});
} }
pub fn with_any_service_label(mut self, labels: Vec<LabelCondition>) -> Self { pub fn with_any_service_label(mut self, labels: Vec<LabelCondition>) -> Self {
self.require_any_service_label(labels); self.require_any_service_label(labels);
@ -402,7 +440,10 @@ impl RuleCondition {
/// Add a service label group that must NOT match (NOT). /// Add a service label group that must NOT match (NOT).
pub fn exclude_service_labels(&mut self, labels: Vec<LabelCondition>) { pub fn exclude_service_labels(&mut self, labels: Vec<LabelCondition>) {
self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::Not, label_group: labels }); self.service_label_groups.push(LabelGroupCondition {
operator: LabelOperator::Not,
label_group: labels,
});
} }
pub fn excluding_service_labels(mut self, labels: Vec<LabelCondition>) -> Self { pub fn excluding_service_labels(mut self, labels: Vec<LabelCondition>) -> Self {
self.exclude_service_labels(labels); self.exclude_service_labels(labels);
@ -414,7 +455,7 @@ impl RuleCondition {
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct MatchCondition { pub struct MatchCondition {
match_on: Vec<String>, match_on: Vec<String>,
operator: MatchOperator operator: MatchOperator,
} }
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
@ -423,14 +464,14 @@ pub struct MatchCondition {
pub enum MatchOperator { pub enum MatchOperator {
#[default] #[default]
OneOf, OneOf,
NoneOf NoneOf,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct HostTagCondition { pub struct HostTagCondition {
key: String, key: String,
match_on: TagMatchOperator match_on: TagMatchOperator,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -446,20 +487,23 @@ pub enum TagMatchOperator {
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct LabelGroupCondition { pub struct LabelGroupCondition {
operator: LabelOperator, operator: LabelOperator,
label_group: Vec<LabelCondition> label_group: Vec<LabelCondition>,
} }
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct LabelCondition { pub struct LabelCondition {
operator: LabelOperator, operator: LabelOperator,
label: String label: String,
} }
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))] #[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum LabelOperator { pub enum LabelOperator {
#[default] And, Or, Not #[default]
And,
Or,
Not,
} }
domain_client!(Rule, rule_api); domain_client!(Rule, rule_api);
@ -469,17 +513,14 @@ domain_delete!(Rule);
impl ApiClient<Rule> { impl ApiClient<Rule> {
pub async fn read(&self, id: Uuid) -> Result<Rule> { pub async fn read(&self, id: Uuid) -> Result<Rule> {
let mut object = self.inner let mut object = self.inner.read_domain_object::<Rule, _>(id, &()).await?;
.read_domain_object::<Rule, _>(id, &())
.await?;
object.extensions.id = Some(Uuid::parse_str(&object.id)?); object.extensions.id = Some(Uuid::parse_str(&object.id)?);
Ok(object.extensions) Ok(object.extensions)
} }
pub async fn bulk_read(&self) -> Result<Vec<Rule>> { pub async fn bulk_read(&self) -> Result<Vec<Rule>> {
let objects = self.inner let objects = self.inner.bulk_read_domain_objects::<Rule, _>(&()).await?;
.bulk_read_domain_objects::<Rule, _>(&()) let objects = objects
.await?; .value
let objects = objects.value
.into_iter() .into_iter()
.map(|mut object| { .map(|mut object| {
object.extensions.id = Some(Uuid::parse_str(&object.id)?); object.extensions.id = Some(Uuid::parse_str(&object.id)?);
@ -491,14 +532,19 @@ impl ApiClient<Rule> {
} }
mod serde_tags { mod serde_tags {
use serde::{Deserialize, Serialize, de::{self, Visitor, Unexpected, Error}, ser::SerializeStruct}; use serde::{
Deserialize, Serialize,
de::{self, Error, Unexpected, Visitor},
ser::SerializeStruct,
};
use crate::api::rules::{HostTagCondition, TagMatchOperator}; use crate::api::rules::{HostTagCondition, TagMatchOperator};
impl Serialize for HostTagCondition { impl Serialize for HostTagCondition {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer { S: serde::Serializer,
{
let mut map = serializer.serialize_struct("HostTagCondition", 3)?; let mut map = serializer.serialize_struct("HostTagCondition", 3)?;
map.serialize_field("key", &self.key)?; map.serialize_field("key", &self.key)?;
@ -507,19 +553,19 @@ mod serde_tags {
TagMatchOperator::Is(value) => { TagMatchOperator::Is(value) => {
map.serialize_field("operator", "is")?; map.serialize_field("operator", "is")?;
map.serialize_field("value", &value)?; map.serialize_field("value", &value)?;
}, }
TagMatchOperator::IsNot(value) => { TagMatchOperator::IsNot(value) => {
map.serialize_field("operator", "is_not")?; map.serialize_field("operator", "is_not")?;
map.serialize_field("value", &value)?; map.serialize_field("value", &value)?;
}, }
TagMatchOperator::OneOff(items) => { TagMatchOperator::OneOff(items) => {
map.serialize_field("operator", "one_of")?; map.serialize_field("operator", "one_of")?;
map.serialize_field("value", items)?; map.serialize_field("value", items)?;
}, }
TagMatchOperator::NoneOff(items) => { TagMatchOperator::NoneOff(items) => {
map.serialize_field("operator", "none_of")?; map.serialize_field("operator", "none_of")?;
map.serialize_field("value", items)?; map.serialize_field("value", items)?;
}, }
}; };
map.end() map.end()
@ -528,7 +574,7 @@ mod serde_tags {
struct HostTagConditionVisitor; struct HostTagConditionVisitor;
impl <'de> Visitor<'de> for HostTagConditionVisitor { impl<'de> Visitor<'de> for HostTagConditionVisitor {
type Value = HostTagCondition; type Value = HostTagCondition;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
@ -537,28 +583,30 @@ mod serde_tags {
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where where
A: serde::de::MapAccess<'de>, { A: serde::de::MapAccess<'de>,
{
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
enum Field { enum Field {
Key, Key,
Operator, Operator,
Value Value,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
enum Operator { enum Operator {
Is, IsNot, OneOff, NoneOff Is,
IsNot,
OneOff,
NoneOff,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum ValueKind { enum ValueKind {
Single(String), Single(String),
Multiple(Vec<String>) Multiple(Vec<String>),
} }
impl ValueKind { impl ValueKind {
@ -572,7 +620,7 @@ mod serde_tags {
fn into_multiple(self) -> Result<Vec<String>, String> { fn into_multiple(self) -> Result<Vec<String>, String> {
match self { match self {
Self::Multiple(ss) => Ok(ss), Self::Multiple(ss) => Ok(ss),
Self::Single(s) => Err(s) Self::Single(s) => Err(s),
} }
} }
} }
@ -584,43 +632,51 @@ mod serde_tags {
while let Some(key) = map.next_key()? { while let Some(key) = map.next_key()? {
#[allow(unused_must_use)] #[allow(unused_must_use)]
match key { match key {
Field::Key => {tkey.insert(map.next_value()?);}, Field::Key => {
Field::Operator => {toperator.insert(map.next_value()?);}, tkey.insert(map.next_value()?);
Field::Value => {tvalue.insert(map.next_value()?);} }
}; Field::Operator => {
toperator.insert(map.next_value()?);
}
Field::Value => {
tvalue.insert(map.next_value()?);
}
}; };
}
let key = tkey.ok_or(A::Error::missing_field("key"))?; let key = tkey.ok_or(A::Error::missing_field("key"))?;
let match_on = match toperator.ok_or(de::Error::missing_field("operator"))? { let match_on = match toperator.ok_or(de::Error::missing_field("operator"))? {
Operator::Is => TagMatchOperator::Is( Operator::Is => TagMatchOperator::Is(
tvalue.and_then(|v| v.into_single()) tvalue
.ok_or(A::Error::invalid_value( .and_then(|v| v.into_single())
Unexpected::Seq, .ok_or(A::Error::invalid_value(Unexpected::Seq, &"single string"))?,
&"single string"
))?
), ),
Operator::IsNot => TagMatchOperator::IsNot( Operator::IsNot => TagMatchOperator::IsNot(
tvalue.and_then(|v| v.into_single()) tvalue
.ok_or(A::Error::invalid_value( .and_then(|v| v.into_single())
Unexpected::Seq, .ok_or(A::Error::invalid_value(Unexpected::Seq, &"single string"))?,
&"single string"
))?
), ),
Operator::OneOff => TagMatchOperator::OneOff( Operator::OneOff => TagMatchOperator::OneOff(
tvalue.ok_or(A::Error::missing_field("value"))? tvalue
.ok_or(A::Error::missing_field("value"))?
.into_multiple() .into_multiple()
.map_err(|s| A::Error::invalid_value( .map_err(|s| {
A::Error::invalid_value(
Unexpected::Str(s.as_str()), Unexpected::Str(s.as_str()),
&"sequence of stirngs" &"sequence of stirngs",
))? )
})?,
), ),
Operator::NoneOff => TagMatchOperator::NoneOff( Operator::NoneOff => TagMatchOperator::NoneOff(
tvalue.ok_or(A::Error::missing_field("value"))? tvalue
.ok_or(A::Error::missing_field("value"))?
.into_multiple() .into_multiple()
.map_err(|s| A::Error::invalid_value( .map_err(|s| {
A::Error::invalid_value(
Unexpected::Str(s.as_str()), Unexpected::Str(s.as_str()),
&"sequence of stirngs" &"sequence of stirngs",
))? )
})?,
), ),
}; };
@ -628,11 +684,11 @@ mod serde_tags {
} }
} }
impl <'de> Deserialize<'de> for HostTagCondition { impl<'de> Deserialize<'de> for HostTagCondition {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de> { D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(HostTagConditionVisitor) deserializer.deserialize_map(HostTagConditionVisitor)
} }
} }

View File

@ -33,7 +33,7 @@ pub enum Error {
#[error("Failed to parse ETag header: {0}")] #[error("Failed to parse ETag header: {0}")]
ParseEtag(#[source] std::string::FromUtf8Error), ParseEtag(#[source] std::string::FromUtf8Error),
#[error("failed to parse domain object id: {0}")] #[error("failed to parse domain object id: {0}")]
ParseId(#[from] uuid::Error) ParseId(#[from] uuid::Error),
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]