Skip to main content

qubit_argument/argument/
option_argument.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Ownership-preserving validation for optional arguments.
9
10use crate::argument::ArgumentError;
11use crate::argument::ArgumentErrorKind;
12use crate::argument::ArgumentResult;
13use crate::argument::internal::Sealed;
14
15/// Validates optional arguments without requiring their values to be cloned.
16///
17/// A required value can be extracted with [`Self::require_some`]. Conditional
18/// validation borrows a present value only for the validator call and returns
19/// the original option on success.
20///
21/// The trait is sealed and implemented only for `Option<T>`.
22pub trait OptionArgument<T>: Sealed + Sized {
23    /// Requires this option to contain a value.
24    ///
25    /// A present value is moved out and returned without cloning. An absent
26    /// value returns [`ArgumentErrorKind::Missing`] at `path`.
27    fn require_some(self, path: &str) -> ArgumentResult<T>;
28
29    /// Validates a present value by temporary borrow.
30    ///
31    /// `validator` receives a shared reference when this option is present. A
32    /// successful validator returns the original option without cloning its
33    /// value; it introduces no failure kind of its own and propagates any
34    /// [`ArgumentErrorKind`] returned by `validator` unchanged. An absent
35    /// option is returned without executing `validator`.
36    fn validate_if_some<F>(self, validator: F) -> ArgumentResult<Self>
37    where
38        F: FnOnce(&T) -> ArgumentResult<()>;
39
40    /// Validates and returns a present owned value.
41    ///
42    /// `validator` receives ownership of the contained value when this option
43    /// is present and must return the validated value. A successful validator
44    /// is wrapped in [`Some`] and returned; it may transform the value without
45    /// requiring [`Clone`] or [`Copy`]. An absent option is returned without
46    /// executing `validator`. Validator errors are propagated unchanged.
47    fn validate_some<F>(self, validator: F) -> ArgumentResult<Self>
48    where
49        F: FnOnce(T) -> ArgumentResult<T>;
50}
51
52impl<T> OptionArgument<T> for Option<T> {
53    /// Extracts a present value or reports that `path` is missing.
54    ///
55    /// The contained value is moved without cloning. An absent option returns
56    /// [`ArgumentErrorKind::Missing`].
57    #[inline]
58    fn require_some(self, path: &str) -> ArgumentResult<T> {
59        match self {
60            Some(value) => Ok(value),
61            None => Err(ArgumentError::new(path, ArgumentErrorKind::Missing)),
62        }
63    }
64
65    /// Borrows and validates a present value, then returns the original option.
66    ///
67    /// A validator error is returned unchanged. When this option is absent,
68    /// `validator` is not executed.
69    #[inline]
70    fn validate_if_some<F>(self, validator: F) -> ArgumentResult<Self>
71    where
72        F: FnOnce(&T) -> ArgumentResult<()>,
73    {
74        if let Some(value) = self.as_ref() {
75            validator(value)?;
76        }
77        Ok(self)
78    }
79
80    /// Moves a present value through `validator` and rewraps it on success.
81    ///
82    /// A validator error is returned unchanged. When this option is absent,
83    /// `validator` is not executed.
84    #[inline]
85    fn validate_some<F>(self, validator: F) -> ArgumentResult<Self>
86    where
87        F: FnOnce(T) -> ArgumentResult<T>,
88    {
89        match self {
90            Some(value) => validator(value).map(Some),
91            None => Ok(None),
92        }
93    }
94}