qubit_argument/argument/argument_path.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//! Structured paths that identify arguments in validation errors.
9
10use std::fmt::{
11 self,
12 Display,
13 Formatter,
14};
15
16/// An owned path identifying an argument or one of its nested components.
17///
18/// The path is stored exactly as supplied; this type does not parse or
19/// normalize separators.
20///
21/// ```compile_fail
22/// #![deny(unused_must_use)]
23/// use qubit_argument::ArgumentPath;
24///
25/// ArgumentPath::new("value");
26/// ```
27#[must_use]
28#[derive(Debug, Clone, PartialEq, Eq, Hash)]
29pub struct ArgumentPath(String);
30
31impl ArgumentPath {
32 /// Creates an argument path by copying `path` without normalization.
33 ///
34 /// # Parameters
35 ///
36 /// - `path`: The path text to store.
37 ///
38 /// # Returns
39 ///
40 /// A new owned argument path.
41 #[inline]
42 pub fn new(path: &str) -> Self {
43 Self(path.to_owned())
44 }
45
46 /// Returns the stored path text.
47 ///
48 /// The returned string slice remains valid for the lifetime of this path.
49 #[inline(always)]
50 pub fn as_str(&self) -> &str {
51 self.0.as_str()
52 }
53
54 /// Prepends a parent path component to this path.
55 ///
56 /// # Parameters
57 ///
58 /// - `prefix`: The parent path to place before the stored path.
59 ///
60 /// # Returns
61 ///
62 /// The composed path. Non-empty components are separated by one dot. If
63 /// either component is empty, no separator is added.
64 #[inline]
65 pub fn with_prefix(self, prefix: &str) -> Self {
66 if prefix.is_empty() {
67 return self;
68 }
69 if self.0.is_empty() {
70 return Self(prefix.to_owned());
71 }
72 let mut path = String::with_capacity(prefix.len() + 1 + self.0.len());
73 path.push_str(prefix);
74 path.push('.');
75 path.push_str(&self.0);
76 Self(path)
77 }
78}
79
80impl AsRef<str> for ArgumentPath {
81 /// Borrows the stored path as a string slice.
82 #[inline(always)]
83 fn as_ref(&self) -> &str {
84 self.as_str()
85 }
86}
87
88impl Display for ArgumentPath {
89 /// Writes the stored path text without additional decoration.
90 #[inline(always)]
91 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
92 formatter.write_str(self.as_str())
93 }
94}