Skip to main content

dex_sdk/
attribute_match.rs

1// Copyright (c) 2026 Super Durable, Inc.
2//
3// Licensed under the Sustainable Use License 1.0.
4// You may not use this file except in compliance with the License.
5// See the LICENSE file in the repository root.
6//
7// SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
9use dex_protocol::dex::{AttributeMatch as ProtoAttributeMatch, AttributeMatchOperator, value};
10
11use crate::{SdkError, SdkResult, Value, value_mapper};
12
13/// Describes a scalar Attribute predicate.
14///
15/// Create a match with an associated factory and pass it to
16/// [`crate::Client::wait_for_attribute_match`] or
17/// [`crate::Client::wait_for_attribute_map_instance_match`]. String and Boolean
18/// Attributes support equality operators. Integer and floating-point Attributes
19/// support every operator. A missing Attribute never matches.
20///
21/// # Examples
22///
23/// ```
24/// use dex_sdk::AttributeMatch;
25///
26/// let changed = AttributeMatch::greater_than(3_i64);
27/// ```
28pub struct AttributeMatch<T> {
29    operator: AttributeMatchOperator,
30    operand: T,
31}
32
33impl<T> AttributeMatch<T> {
34    /// Creates an equality match.
35    pub fn equal_to(operand: T) -> Self {
36        Self::new(AttributeMatchOperator::Equal, operand)
37    }
38
39    /// Creates a not-equal match. A missing Attribute does not match.
40    pub fn not_equal_to(operand: T) -> Self {
41        Self::new(AttributeMatchOperator::NotEqual, operand)
42    }
43
44    /// Creates a numeric greater-than match.
45    pub fn greater_than(operand: T) -> Self {
46        Self::new(AttributeMatchOperator::GreaterThan, operand)
47    }
48
49    /// Creates a numeric greater-than-or-equal match.
50    pub fn greater_than_or_equal(operand: T) -> Self {
51        Self::new(AttributeMatchOperator::GreaterThanOrEqual, operand)
52    }
53
54    /// Creates a numeric less-than match.
55    pub fn less_than(operand: T) -> Self {
56        Self::new(AttributeMatchOperator::LessThan, operand)
57    }
58
59    /// Creates a numeric less-than-or-equal match.
60    pub fn less_than_or_equal(operand: T) -> Self {
61        Self::new(AttributeMatchOperator::LessThanOrEqual, operand)
62    }
63
64    fn new(operator: AttributeMatchOperator, operand: T) -> Self {
65        Self { operator, operand }
66    }
67}
68
69impl<T: Value> AttributeMatch<T> {
70    pub(crate) fn encode(&self) -> SdkResult<ProtoAttributeMatch> {
71        let operand = value_mapper::encode(&self.operand)?;
72        let is_ordering = self.operator >= AttributeMatchOperator::GreaterThan;
73        match operand.kind.as_ref() {
74            Some(value::Kind::StringValue(_) | value::Kind::BoolValue(_)) if is_ordering => {
75                return Err(invalid(
76                    "AttributeMatch ordering requires an integer or floating-point operand",
77                ));
78            }
79            Some(
80                value::Kind::StringValue(_)
81                | value::Kind::BoolValue(_)
82                | value::Kind::IntValue(_)
83                | value::Kind::DoubleValue(_),
84            ) => {}
85            _ => {
86                return Err(invalid(
87                    "AttributeMatch supports only string, Boolean, integer, or floating-point operands",
88                ));
89            }
90        }
91        Ok(ProtoAttributeMatch {
92            key: String::new(),
93            operator: self.operator as i32,
94            operand: Some(operand),
95        })
96    }
97}
98
99fn invalid(message: impl Into<String>) -> SdkError {
100    SdkError::InvalidArgument {
101        message: message.into(),
102    }
103}