Skip to main content

pvxs_sys/
value.rs

1// Copyright 2026 Tine Zata
2// SPDX-License-Identifier: MPL-2.0
3use cxx::UniquePtr;
4use std::fmt;
5
6use crate::{bridge, Result};
7
8/// A PVAccess value container
9///
10/// Represents a structured data value returned from PVXS operations.
11/// Values have a hierarchical structure with named fields.
12///
13/// # Field Access
14///
15/// Values are accessed by field name. Common fields include:
16/// - `"value"`: The primary data value
17/// - `"alarm.severity"`: Alarm severity level
18/// - `"alarm.status"`: Alarm status code
19/// - `"timeStamp.secondsPastEpoch"`: Timestamp seconds
20///
21/// # Example
22///
23/// ```no_run
24/// # use pvxs_sys::{Context, Value};
25/// # let mut ctx = Context::from_env().unwrap();
26/// let value: Value = ctx.get("my:pv:name", 5.0).unwrap();
27///
28/// // Access different field types
29/// let v = value.get_field_double("value").unwrap();
30/// let severity = value.get_field_int32("alarm.severity").unwrap();
31/// ```
32pub struct Value {
33    pub(crate) inner: UniquePtr<bridge::ValueWrapper>,
34}
35
36impl Value {
37    /// Check if this value is valid
38    ///
39    /// Returns `false` if the value is empty or uninitialized.
40    pub fn is_valid(&self) -> bool {
41        bridge::value_is_valid(&self.inner)
42    }
43
44    /// Get a field value as a double
45    ///
46    /// # Errors
47    ///
48    /// Returns an error if the field doesn't exist or cannot be
49    /// converted to a double.
50    pub fn get_field_double(&self, field_name: &str) -> Result<f64> {
51        Ok(bridge::value_get_field_double(
52            &self.inner,
53            field_name.to_string(),
54        )?)
55    }
56
57    /// Get a field value as an i32
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the field doesn't exist or cannot be
62    /// converted to an i32.
63    pub fn get_field_int32(&self, field_name: &str) -> Result<i32> {
64        Ok(bridge::value_get_field_int32(
65            &self.inner,
66            field_name.to_string(),
67        )?)
68    }
69
70    /// Get a field value as a String
71    ///
72    /// # Errors
73    ///
74    /// Returns an error if the field doesn't exist or cannot be
75    /// converted to a string.
76    pub fn get_field_string(&self, field_name: &str) -> Result<String> {
77        Ok(bridge::value_get_field_string(
78            &self.inner,
79            field_name.to_string(),
80        )?)
81    }
82
83    /// Get a field value as a enum
84    ///
85    /// # Errors
86    ///
87    /// Returns an error if the field doesn't exist or cannot be
88    /// converted to a enum.
89    pub fn get_field_enum(&self, field_name: &str) -> Result<i16> {
90        Ok(bridge::value_get_field_enum(
91            &self.inner,
92            field_name.to_string(),
93        )?)
94    }
95
96    /// Get a field value as an array of doubles
97    ///
98    /// Extracts a field containing an array of double-precision floating point values.
99    /// Commonly used for waveform data, measurement arrays, or multi-point setpoints.
100    ///
101    /// # Arguments
102    ///
103    /// * `field_name` - The field path (e.g., "value", "waveform.data")
104    ///
105    /// # Errors
106    ///
107    /// Returns an error if the field doesn't exist or cannot be
108    /// converted to an array of doubles.
109    ///
110    /// # Example
111    ///
112    /// ```no_run
113    /// # use pvxs_sys::Context;
114    /// # let mut ctx = Context::from_env().unwrap();
115    /// let value = ctx.get("waveform:double:pv", 5.0).unwrap();
116    /// let array = value.get_field_double_array("value").unwrap();
117    /// println!("Double array length: {}", array.len());
118    /// for (i, val) in array.iter().enumerate().take(5) {
119    ///     println!("  [{}] = {}", i, val);
120    /// }
121    /// ```
122    pub fn get_field_double_array(&self, field_name: &str) -> Result<Vec<f64>> {
123        Ok(bridge::value_get_field_double_array(
124            &self.inner,
125            field_name.to_string(),
126        )?)
127    }
128
129    /// Get a field value as an array of int32
130    ///
131    /// Extracts a field containing an array of 32-bit signed integers.
132    /// Often used for status arrays, configuration parameters, or indexed data.
133    ///
134    /// # Arguments
135    ///
136    /// * `field_name` - The field path (e.g., "value", "status.codes")
137    ///
138    /// # Errors
139    ///
140    /// Returns an error if the field doesn't exist or cannot be
141    /// converted to an array of int32.
142    ///
143    /// # Example
144    ///
145    /// ```no_run
146    /// # use pvxs_sys::Context;
147    /// # let mut ctx = Context::from_env().unwrap();
148    /// let value = ctx.get("array:int32:pv", 5.0).unwrap();
149    /// let array = value.get_field_int32_array("value").unwrap();
150    /// println!("Int32 array length: {}", array.len());
151    /// for (i, val) in array.iter().enumerate().take(5) {
152    ///     println!("  [{}] = {}", i, val);
153    /// }
154    /// ```
155    pub fn get_field_int32_array(&self, field_name: &str) -> Result<Vec<i32>> {
156        Ok(bridge::value_get_field_int32_array(
157            &self.inner,
158            field_name.to_string(),
159        )?)
160    }
161
162    /// Get a field value as an array of strings
163    ///
164    /// Extracts a field containing an array of string values.
165    /// Commonly used for enum choices, device names, status messages, or text lists.
166    ///
167    /// # Arguments
168    ///
169    /// * `field_name` - The field path (e.g., "value.choices", "devices.names")
170    ///
171    /// # Errors
172    ///
173    /// Returns an error if the field doesn't exist or cannot be
174    /// converted to an array of strings.
175    ///
176    /// # Example
177    ///
178    /// ```no_run
179    /// # use pvxs_sys::Context;
180    /// # let mut ctx = Context::from_env().unwrap();
181    /// // Get enum choices for an NTEnum PV
182    /// let value = ctx.get("enum:pv", 5.0).unwrap();
183    /// let choices = value.get_field_string_array("value.choices").unwrap();
184    /// println!("Available choices:");
185    /// for (i, choice) in choices.iter().enumerate() {
186    ///     println!("  [{}] = '{}'", i, choice);
187    /// }
188    /// ```
189    pub fn get_field_string_array(&self, field_name: &str) -> Result<Vec<String>> {
190        Ok(bridge::value_get_field_string_array(
191            &self.inner,
192            field_name.to_string(),
193        )?)
194    }
195}
196
197impl fmt::Display for Value {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        write!(f, "{}", bridge::value_to_string(&self.inner))
200    }
201}
202
203impl fmt::Debug for Value {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        f.debug_struct("Value")
206            .field("data", &bridge::value_to_string(&self.inner))
207            .finish()
208    }
209}