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