Skip to main content

hapi_rs/parameter/
mod.rs

1//! Reading and setting node parameters, setting expressions and keyframes.
2//!
3//! Different parameter types are modeled with a [Parameter] enum, to get to a concrete type,
4//! use pattern matching:
5//!
6//! ```
7//! use hapi_rs::session::new_in_process_session;
8//! use hapi_rs::session::SessionOptions;
9//! use hapi_rs::parameter::*;
10//! let session = new_in_process_session(Some(SessionOptions::default())).unwrap();
11//! let lib = session.load_asset_file("../otls/hapi_parms.hda").unwrap();
12//! let node = lib.try_create_first().unwrap();
13//! if let Parameter::String(p) = node.parameter("single_string").unwrap() {
14//!     assert_eq!(p.get(0).unwrap(), "hello");
15//!     assert!(p.set(0, "world").is_ok());
16//! }
17//! ```
18//! Extra parameter features are available in [`ParmBaseTrait`]
19
20mod base;
21mod access;
22
23use crate::Result;
24pub use crate::ffi::enums::ParmType;
25pub use crate::ffi::structs::{KeyFrame, ParmInfo};
26use crate::node::{HoudiniNode, NodeHandle, Session};
27pub use base::*;
28use std::fmt::Debug;
29
30/// An internal handle to a parameter
31#[repr(transparent)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct ParmHandle(pub crate::ffi::raw::HAPI_ParmId);
34
35#[derive(Debug)]
36/// Enum of different parameter types.
37pub enum Parameter {
38    /// `ParmType::Float | ParmType::Color`
39    Float(FloatParameter),
40    /// `ParmType::Int | ParmType::Toggle`
41    Int(IntParameter),
42    /// `ParmType::String | ParmType::Node | ParmType::PathFile | ParmType::PathFileDir | ParmType::PathFileGeo | ParmType::PathFileImage`
43    String(StringParameter),
44    /// `ParmType::Int`
45    Button(IntParameter),
46    /// `Other ParmType::_`
47    Other(BaseParameter),
48}
49
50impl Parameter {
51    pub(crate) fn new(node: NodeHandle, info: ParmInfo) -> Parameter {
52        let wrap = ParmInfoWrap { info, node };
53        match wrap.info.parm_type() {
54            ParmType::Int | ParmType::Toggle | ParmType::Multiparmlist => {
55                Parameter::Int(IntParameter(wrap))
56            }
57            ParmType::Button => Parameter::Button(IntParameter(wrap)),
58            ParmType::Float | ParmType::Color => Parameter::Float(FloatParameter(wrap)),
59            ParmType::String
60            | ParmType::Node
61            | ParmType::PathFile
62            | ParmType::PathFileDir
63            | ParmType::PathFileGeo
64            | ParmType::PathFileImage => Parameter::String(StringParameter(wrap)),
65            _ => Parameter::Other(BaseParameter(wrap)),
66        }
67    }
68
69    /// A convenient method to evaluate a parameter value as string for debugging.
70    pub fn value_as_debug(&self) -> Result<Box<dyn Debug>> {
71        match self {
72            Parameter::Float(parm) => Ok(Box::new(parm.get_array()?)),
73            Parameter::Int(parm) | Parameter::Button(parm) => Ok(Box::new(parm.get_array()?)),
74            Parameter::String(parm) => Ok(Box::new(parm.get_array()?)),
75            Parameter::Other(parm) => Ok(Box::new(parm.0.info.parm_type())),
76        }
77    }
78    /// Information about the parameter
79    #[inline]
80    #[must_use]
81    pub fn info(&self) -> &ParmInfo {
82        &self.base().info
83    }
84
85    /// Parameter internal name
86    #[inline]
87    pub fn name(&self) -> Result<String> {
88        self.info().name()
89    }
90
91    /// Parameter UI label
92    #[inline]
93    pub fn label(&self) -> Result<String> {
94        self.info().label()
95    }
96
97    /// Number or elements in the parameter
98    #[inline]
99    #[must_use]
100    pub fn size(&self) -> i32 {
101        self.info().size()
102    }
103
104    /// Parameter parent if any (examples are multi-parm or Folder type parameters)
105    pub fn parent(&self) -> Result<Option<ParmInfo>> {
106        let wrap = self.base();
107        debug_assert!(wrap.info.1.is_valid());
108        match wrap.info.parent_id() {
109            ParmHandle(-1) => Ok(None),
110            handle => {
111                let session = wrap.info.1.clone();
112                let info = crate::ffi::get_parm_info(wrap.node, &session, handle)?;
113                Ok(Some(ParmInfo(info, session, None)))
114            }
115        }
116    }
117
118    pub(crate) fn base(&self) -> &ParmInfoWrap {
119        #[allow(clippy::match_same_arms)]
120        match self {
121            Parameter::Float(p) => &p.0,
122            Parameter::Int(p) => &p.0,
123            Parameter::Button(p) => &p.0,
124            Parameter::String(p) => &p.0,
125            Parameter::Other(p) => &p.0,
126        }
127    }
128}
129
130impl ParmBaseTrait for Parameter {
131    fn inner(&self) -> &ParmInfoWrap {
132        self.base()
133    }
134
135    fn inner_mut(&mut self) -> &mut ParmInfoWrap {
136        #[allow(clippy::match_same_arms)]
137        match self {
138            Parameter::Float(p) => &mut p.0,
139            Parameter::Int(p) => &mut p.0,
140            Parameter::Button(p) => &mut p.0,
141            Parameter::String(p) => &mut p.0,
142            Parameter::Other(p) => &mut p.0,
143        }
144    }
145}
146
147impl ParmHandle {
148    /// Find a parameter handle by name
149    pub fn from_name(name: &str, node: &HoudiniNode) -> Result<Self> {
150        debug_assert!(node.is_valid()?);
151        let name = std::ffi::CString::new(name)?;
152        let id = crate::ffi::get_parm_id_from_name(&name, node.handle, &node.session)?;
153        Ok(ParmHandle(id))
154    }
155    /// Retrieve parameter information from of the handle
156    pub fn info(&self, node: &HoudiniNode) -> Result<ParmInfo> {
157        debug_assert!(node.is_valid()?);
158        let info = crate::ffi::get_parm_info(node.handle, &node.session, *self)?;
159        Ok(ParmInfo::new(info, node.session.clone(), None))
160    }
161}
162
163impl ParmInfo {
164    pub(crate) fn from_parm_name(name: &str, node: &HoudiniNode) -> Result<Self> {
165        debug_assert!(node.is_valid()?);
166        let name = std::ffi::CString::new(name)?;
167        let info = crate::ffi::get_parm_info_from_name(node.handle, &node.session, &name);
168        info.map(|info| ParmInfo::new(info, node.session.clone(), Some(name)))
169    }
170
171    pub(crate) fn from_parm_handle(
172        parm: ParmHandle,
173        node: NodeHandle,
174        session: &Session,
175    ) -> Result<Self> {
176        let parm_info = crate::ffi::get_parm_info(node, session, parm)?;
177        Ok(ParmInfo::new(parm_info, session.clone(), None))
178    }
179}