use super::*;
use std::ffi::{ CStr, CString };
use ae_sys::PF_PathID;
use serde::{de::DeserializeOwned, Serialize};
#[cfg(target_os = "macos")]
use objc2_core_foundation::{CFRange, CFString};
const MAX_NAME_LEN: usize = 32;
define_enum! {
ae_sys::PF_ParamType,
ParamType {
Reserved = ae_sys::PF_Param_RESERVED,
Layer = ae_sys::PF_Param_LAYER,
Slider = ae_sys::PF_Param_SLIDER,
FixSlider = ae_sys::PF_Param_FIX_SLIDER,
Angle = ae_sys::PF_Param_ANGLE,
CheckBox = ae_sys::PF_Param_CHECKBOX,
Color = ae_sys::PF_Param_COLOR,
Point = ae_sys::PF_Param_POINT,
PopUp = ae_sys::PF_Param_POPUP,
Custom = ae_sys::PF_Param_CUSTOM,
NoData = ae_sys::PF_Param_NO_DATA,
FloatSlider = ae_sys::PF_Param_FLOAT_SLIDER,
ArbitraryData = ae_sys::PF_Param_ARBITRARY_DATA,
Path = ae_sys::PF_Param_PATH,
GroupStart = ae_sys::PF_Param_GROUP_START,
GroupEnd = ae_sys::PF_Param_GROUP_END,
Button = ae_sys::PF_Param_BUTTON,
Reserved2 = ae_sys::PF_Param_RESERVED2,
Reserved3 = ae_sys::PF_Param_RESERVED3,
Point3D = ae_sys::PF_Param_POINT_3D,
}
}
bitflags! {
pub struct ParamUIFlags: ae_sys::A_long {
const NONE = ae_sys::PF_PUI_NONE as ae_sys::A_long;
const TOPIC = ae_sys::PF_PUI_TOPIC as ae_sys::A_long;
const CONTROL = ae_sys::PF_PUI_CONTROL as ae_sys::A_long;
const CONTROL_ONLY = ae_sys::PF_PUI_STD_CONTROL_ONLY as ae_sys::A_long;
const NO_ECW_UI = ae_sys::PF_PUI_NO_ECW_UI as ae_sys::A_long;
const ECW_SEPARATOR = ae_sys::PF_PUI_ECW_SEPARATOR as ae_sys::A_long;
const DISABLED = ae_sys::PF_PUI_DISABLED as ae_sys::A_long;
const DO_NOT_ERASE_TOPIC = ae_sys::PF_PUI_DONT_ERASE_TOPIC as ae_sys::A_long;
const DO_NOT_ERASE_CONTROL = ae_sys::PF_PUI_DONT_ERASE_CONTROL as ae_sys::A_long;
const RADIO_BUTTON = ae_sys::PF_PUI_RADIO_BUTTON as ae_sys::A_long;
const INVISIBLE = ae_sys::PF_PUI_INVISIBLE as ae_sys::A_long;
}
}
bitflags! {
pub struct ParamFlag: ae_sys::A_long {
const CANNOT_TIME_VARY = ae_sys::PF_ParamFlag_CANNOT_TIME_VARY as ae_sys::A_long;
const CANNOT_INTERP = ae_sys::PF_ParamFlag_CANNOT_INTERP as ae_sys::A_long;
const TWIRLY = ae_sys::PF_ParamFlag_COLLAPSE_TWIRLY as ae_sys::A_long;
const SUPERVISE = ae_sys::PF_ParamFlag_SUPERVISE as ae_sys::A_long;
const START_COLLAPSED = ae_sys::PF_ParamFlag_START_COLLAPSED as ae_sys::A_long;
const USE_VALUE_FOR_OLD_PROJECTS = ae_sys::PF_ParamFlag_USE_VALUE_FOR_OLD_PROJECTS as ae_sys::A_long;
const LAYER_PARAM_IS_TRACKMATTE = ae_sys::PF_ParamFlag_LAYER_PARAM_IS_TRACKMATTE as ae_sys::A_long;
const EXCLUDE_FROM_HAVE_INPUTS_CHANGED = ae_sys::PF_ParamFlag_EXCLUDE_FROM_HAVE_INPUTS_CHANGED as ae_sys::A_long;
const SKIP_REVEAL_WHEN_UNHIDDEN = ae_sys::PF_ParamFlag_SKIP_REVEAL_WHEN_UNHIDDEN as ae_sys::A_long;
}
}
bitflags! {
pub struct ChangeFlag: ae_sys::A_long {
const NONE = ae_sys::PF_ChangeFlag_NONE as ae_sys::A_long;
const CHANGED_VALUE = ae_sys::PF_ChangeFlag_CHANGED_VALUE as ae_sys::A_long;
const SET_TO_VARY = ae_sys::PF_ChangeFlag_SET_TO_VARY as ae_sys::A_long;
const SET_TO_CONSTANT = ae_sys::PF_ChangeFlag_SET_TO_CONSTANT as ae_sys::A_long;
}
}
bitflags! {
pub struct ValueDisplayFlag: u16 {
const NONE = ae_sys::PF_ValueDisplayFlag_NONE as u16;
const PERCENT = ae_sys::PF_ValueDisplayFlag_PERCENT as u16;
const PIXEL = ae_sys::PF_ValueDisplayFlag_PIXEL as u16;
const REVERSE = ae_sys::PF_ValueDisplayFlag_REVERSE as u16;
}
}
bitflags! {
pub struct FSliderFlag: u16 {
const NONE = ae_sys::PF_FSliderFlag_NONE as u16;
const WANT_PHASE = ae_sys::PF_FSliderFlag_WANT_PHASE as u16;
}
}
define_param_wrapper! {
PF_Param_ANGLE, PF_AngleDef, ad,
Param::Angle,
AngleDef { },
impl value: Fixed,
}
impl AngleDef<'_> {
pub fn set_default(&mut self, v: f32) -> &mut Self {
self.def.dephault = Fixed::from(v).as_fixed();
self
}
pub fn default(&self) -> f32 {
Fixed::from_fixed(self.def.dephault).into()
}
pub fn float_value(&self) -> Result<f64, Error> {
if self._in_data.is_null() || self._parent_ptr.is_none() {
return Err(Error::InvalidParms);
}
Ok(pf::suites::AngleParam::new()?
.floating_point_value_from_angle_def(unsafe { (*self._in_data).effect_ref }, self._parent_ptr.unwrap())?)
}
}
define_param_wrapper! {
PF_Param_BUTTON, PF_ButtonDef, button_d,
Param::Button,
ButtonDef {
label: CString,
},
impl label: String,
}
define_param_wrapper! {
PF_Param_CHECKBOX, PF_CheckBoxDef, bd,
Param::CheckBox,
CheckBoxDef {
label: CString,
},
impl value: bool,
fn init(param) {
param.set_label(" ");
}
}
impl<'a> CheckBoxDef<'_> {
pub fn set_default(&mut self, v: bool) -> &mut Self {
self.def.dephault = if v { 1 } else { 0 };
self
}
pub fn default(&self) -> bool {
self.def.dephault != 0
}
pub fn set_label(&mut self, v: &str) -> &mut Self {
self.label = CString::new(v).unwrap();
self.def.u.nameptr = self.label.as_ptr();
self
}
pub fn label(&self) -> &str {
unsafe { CStr::from_ptr(self.def.u.nameptr).to_str().unwrap() }
}
}
define_param_wrapper! {
PF_Param_COLOR, PF_ColorDef, cd,
Param::Color,
ColorDef { },
impl value: Pixel8,
impl default: Pixel8,
}
impl ColorDef<'_> {
pub fn float_value(&self) -> Result<PixelF32, Error> {
if self._in_data.is_null() || self._parent_ptr.is_none() {
return Err(Error::InvalidParms);
}
Ok(pf::suites::ColorParam::new()?
.floating_point_value_from_color_def(unsafe { (*self._in_data).effect_ref }, self._parent_ptr.unwrap())?)
}
}
define_param_wrapper! {
PF_Param_SLIDER, PF_SliderDef, sd,
Param::Slider,
SliderDef { },
impl value: i32,
impl default: i32,
impl valid_min: i32,
impl valid_max: i32,
impl slider_min: i32,
impl slider_max: i32,
impl value_str: ShortString,
impl value_desc: ShortString,
}
define_param_wrapper! {
PF_Param_FLOAT_SLIDER, PF_FloatSliderDef, fs_d,
Param::FloatSlider,
FloatSliderDef { },
impl value: f64,
impl phase: f64,
impl default: f64,
impl precision: i16,
impl curve_tolerance: f32,
impl valid_min: f32,
impl valid_max: f32,
impl slider_min: f32,
impl slider_max: f32,
impl value_desc: ShortString,
}
impl FloatSliderDef<'_> {
pub fn set_display_flags(&mut self, flags: ValueDisplayFlag) -> &mut Self {
self.def.display_flags = flags.bits() as _;
self
}
pub fn display_flags(&self) -> ValueDisplayFlag {
ValueDisplayFlag::from_bits_truncate(self.def.display_flags as _)
}
pub fn set_flags(&mut self, flags: FSliderFlag) -> &mut Self {
self.def.fs_flags = flags.bits() as _;
self
}
pub fn flags(&self) -> FSliderFlag {
FSliderFlag::from_bits_truncate(self.def.fs_flags as _)
}
pub fn set_exponent(&mut self, v: f32) -> &mut Self {
self.def.exponent = v;
self.def.useExponent = 1;
self
}
pub fn exponent(&self) -> Option<f32> {
if self.def.useExponent == 1 {
Some(self.def.exponent)
} else {
None
}
}
}
#[allow(non_upper_case_globals, non_snake_case)]
pub mod Precision {
pub const Integer: i16 = 0;
pub const Tenths: i16 = 1;
pub const Hundredths: i16 = 2;
pub const Thousandths: i16 = 3;
pub const TenThousandths: i16 = 4;
}
define_param_wrapper! {
PF_Param_PATH, PF_PathDef, path_d,
Param::Path,
PathDef { },
impl path_id: PF_PathID,
impl default: i32,
}
define_param_wrapper! {
PF_Param_POINT, PF_PointDef, td,
Param::Point,
PointDef { },
impl restrict_bounds: bool,
impl x_value: Fixed,
impl y_value: Fixed,
}
impl PointDef<'_> {
pub fn set_default_x(&mut self, v: f32) -> &mut Self { self.def.x_dephault = Fixed::from(v).as_fixed(); self }
pub fn set_default_y(&mut self, v: f32) -> &mut Self { self.def.y_dephault = Fixed::from(v).as_fixed(); self }
pub fn default_x(&self) -> f32 { Fixed::from_fixed(self.def.x_dephault).into() }
pub fn default_y(&self) -> f32 { Fixed::from_fixed(self.def.y_dephault).into() }
pub fn set_default(&mut self, v: (f32, f32)) -> &mut Self {
self.def.x_dephault = Fixed::from(v.0).as_fixed();
self.def.y_dephault = Fixed::from(v.1).as_fixed();
self
}
pub fn default(&self) -> (f32, f32) {
(Fixed::from_fixed(self.def.x_dephault).into(), Fixed::from_fixed(self.def.y_dephault).into())
}
pub fn set_value(&mut self, v: (f32, f32)) -> &mut Self {
self.def.x_value = Fixed::from(v.0).as_fixed();
self.def.y_value = Fixed::from(v.1).as_fixed();
self
}
pub fn value(&self) -> (f32, f32) {
(Fixed::from_fixed(self.def.x_value).into(), Fixed::from_fixed(self.def.y_value).into())
}
pub fn float_value(&self) -> Result<ae_sys::A_FloatPoint, Error> {
if self._in_data.is_null() || self._parent_ptr.is_none() {
return Err(Error::InvalidParms);
}
Ok(pf::suites::PointParam::new()?
.floating_point_value_from_point_def(unsafe { (*self._in_data).effect_ref }, self._parent_ptr.unwrap())?)
}
}
define_param_wrapper! {
PF_Param_POINT_3D, PF_Point3DDef, point3d_d,
Param::Point3D,
Point3DDef { },
impl x_value: f64,
impl y_value: f64,
impl z_value: f64,
}
impl Point3DDef<'_> {
pub fn set_default_x(&mut self, v: f64) -> &mut Self { self.def.x_dephault = v; self }
pub fn set_default_y(&mut self, v: f64) -> &mut Self { self.def.y_dephault = v; self }
pub fn set_default_z(&mut self, v: f64) -> &mut Self { self.def.z_dephault = v; self }
pub fn default_x(&self) -> f64 { self.def.x_dephault }
pub fn default_y(&self) -> f64 { self.def.y_dephault }
pub fn default_z(&self) -> f64 { self.def.z_dephault }
pub fn set_default(&mut self, v: (f64, f64, f64)) -> &mut Self {
self.def.x_dephault = v.0;
self.def.y_dephault = v.1;
self.def.z_dephault = v.2;
self
}
pub fn default(&self) -> (f64, f64, f64) {
(self.def.x_dephault, self.def.y_dephault, self.def.z_dephault)
}
pub fn set_value(&mut self, v: (f64, f64, f64)) -> &mut Self {
self.def.x_value = v.0;
self.def.y_value = v.1;
self.def.z_value = v.2;
self
}
pub fn value(&self) -> (f64, f64, f64) {
(self.def.x_value, self.def.y_value, self.def.z_value)
}
}
define_param_wrapper! {
PF_Param_POPUP, PF_PopupDef, pd,
Param::Popup,
PopupDef {
options: CString,
},
impl value: i32,
impl default: i32,
}
impl<'a> PopupDef<'a> {
pub fn set_options(&mut self, options: &[&str]) {
self.options = CString::new(options.join("|")).unwrap();
self.def.u.namesptr = self.options.as_ptr();
self.def.num_choices = options.len().try_into().unwrap();
}
pub fn options(&self) -> Vec<&str> {
let options = unsafe { CStr::from_ptr(self.def.u.namesptr).to_str().unwrap() };
options.split('|').collect()
}
}
define_param_wrapper! {
PF_Param_LAYER, PF_LayerDef, ld,
Param::Layer,
LayerDef { },
}
impl<'a> LayerDef<'a> {
pub fn set_default_to_this_layer(&mut self) {
self.def.dephault = ae_sys::PF_LayerDefault_MYSELF;
}
pub fn value(&self) -> Option<Layer> {
if self.def.data.is_null() {
None
} else {
Some(Layer::from_raw(&*self.def as *const _ as _, self._in_data, None))
}
}
}
#[allow(dead_code)]
pub struct NullDef<'a>(&'a ());
impl<'a> NullDef<'a> {
pub fn new() -> Self {
Self(&())
}
}
impl<'p> Into<Param<'p>> for NullDef<'p> {
fn into(self) -> Param<'p> {
Param::Null(self)
}
}
define_param_wrapper! {
PF_Param_ARBITRARY_DATA, PF_ArbitraryDef, arb_d,
Param::Arbitrary,
ArbitraryDef { },
impl pad: i16,
}
impl ArbitraryDef<'_> {
pub fn set_default<T>(&mut self, value: T) -> Result<&mut Self, Error> {
self.def.dephault = Handle::into_raw(Handle::new(value)?);
Ok(self)
}
pub fn set_value<T>(&mut self, value: T) -> Result<&mut Self, Error> {
if !self.def.value.is_null() {
let _ = Handle::<T>::from_raw(self.def.value, true);
}
self.def.value = Handle::into_raw(Handle::new(value)?);
self.set_value_changed();
Ok(self)
}
pub fn value<T>(&self) -> Result<BorrowedHandleLock<T>, Error> {
if self.def.value.is_null() {
return Err(Error::InvalidParms);
}
BorrowedHandleLock::<T>::from_raw(self.def.value)
}
pub fn set_refcon(&mut self, refcon: *mut std::ffi::c_void) -> &mut Self {
self.def.refconPV = refcon as _;
self
}
}
pub trait ArbitraryData<T> {
fn interpolate(&self, other: &T, value: f64) -> T;
}
define_struct_wrapper!(ArbParamsExtra, PF_ArbParamsExtra);
impl std::fmt::Debug for ArbParamsExtra {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ArbParamsExtra")
.field("id", &self.id())
.field("refcon", &self.refcon())
.field("which_function", &self.which_function())
.finish()
}
}
impl ArbParamsExtra {
pub fn id(&self) -> i16 {
self.as_ref().id as _
}
pub fn refcon(&self) -> *mut std::ffi::c_void {
unsafe { self.as_ref().u.new_func_params.refconPV }
}
pub fn which_function(&self) -> u32 {
self.as_ref().which_function as _
}
pub fn dispatch<T, P>(&mut self, param: P) -> Result<(), Error>
where T: ArbitraryData<T> + Default + DeserializeOwned + Serialize + PartialEq + PartialOrd,
P: Eq + PartialEq + Hash + Copy + Debug
{
let param_id = Parameters::param_id(param) as i16;
if self.id() != param_id {
return Ok(());
}
match self.as_ref().which_function as _ {
ae_sys::PF_Arbitrary_NEW_FUNC => unsafe {
assert!(!self.as_ref().u.new_func_params.arbPH.is_null());
self.as_ref()
.u
.new_func_params
.arbPH
.write(Handle::into_raw(Handle::<T>::new(T::default())?));
},
ae_sys::PF_Arbitrary_DISPOSE_FUNC => {
if unsafe { !self.as_ref().u.dispose_func_params.arbH.is_null() } {
Handle::<T>::from_raw(unsafe { self.as_ref().u.dispose_func_params.arbH }, true)?;
}
}
ae_sys::PF_Arbitrary_COPY_FUNC => unsafe {
if self.as_ref().u.copy_func_params.src_arbH.is_null() {
self.as_ref()
.u
.copy_func_params
.dst_arbPH
.write(Handle::into_raw(Handle::<T>::new(T::default())?));
return Ok(());
}
let mut src_handle = Handle::<T>::from_raw(self.as_ref().u.copy_func_params.src_arbH, false)?;
let lock = src_handle.lock()?;
let serialized = bincode::serde::encode_to_vec::<&T, _>(lock.as_ref()?, bincode::config::legacy()).map_err(|_| Error::InternalStructDamaged)?;
let deserialized = bincode::serde::decode_from_slice::<T, _>(&serialized, bincode::config::legacy()).map_err(|_| Error::InternalStructDamaged)?;
let new_handle = Handle::<T>::new(deserialized.0)?;
self.as_ref()
.u
.copy_func_params
.dst_arbPH
.write(Handle::into_raw(new_handle));
},
ae_sys::PF_Arbitrary_FLAT_SIZE_FUNC => unsafe {
let mut handle = Handle::<T>::from_raw(self.as_ref().u.flat_size_func_params.arbH, false)?;
let lock = handle.lock()?;
let serialized = bincode::serde::encode_to_vec::<&T, _>(lock.as_ref()?, bincode::config::legacy()).map_err(|_| Error::InternalStructDamaged)?;
self.as_ref()
.u
.flat_size_func_params
.flat_data_sizePLu
.write(serialized.len() as _);
},
ae_sys::PF_Arbitrary_FLATTEN_FUNC => unsafe {
assert!(!self.as_ref().u.unflatten_func_params.flat_dataPV.is_null());
let mut handle = Handle::<T>::from_raw(self.as_ref().u.flatten_func_params.arbH, false)?;
let lock = handle.lock()?;
let serialized = bincode::serde::encode_to_vec::<&T, _>(lock.as_ref()?, bincode::config::legacy()).map_err(|_| Error::InternalStructDamaged)?;
assert!(
serialized.len() <= self.as_ref().u.flatten_func_params.buf_sizeLu as _
);
std::ptr::copy_nonoverlapping(
serialized.as_ptr(),
self.as_ref().u.flatten_func_params.flat_dataPV as _,
serialized.len(),
);
}
ae_sys::PF_Arbitrary_UNFLATTEN_FUNC => unsafe {
assert!(!self.as_ref().u.unflatten_func_params.flat_dataPV.is_null());
let serialized = std::slice::from_raw_parts(
self.as_ref().u.unflatten_func_params.flat_dataPV as *mut u8,
self.as_ref().u.unflatten_func_params.buf_sizeLu as _
);
let t = bincode::serde::decode_from_slice::<T, _>(serialized, bincode::config::legacy()).map_err(|_| Error::InternalStructDamaged)?;
let handle = Handle::<T>::new(t.0)?;
self.as_ref()
.u
.unflatten_func_params
.arbPH
.write(Handle::into_raw(handle));
},
ae_sys::PF_Arbitrary_INTERP_FUNC => unsafe {
let mut left = Handle::<T>::from_raw(self.as_ref().u.interp_func_params.left_arbH, false)?;
let left_lock = left.lock()?;
let mut right = Handle::<T>::from_raw(self.as_ref().u.interp_func_params.right_arbH, false)?;
let right_lock = right.lock()?;
let interpolated = Handle::<T>::new(
left_lock.as_ref()?.interpolate(right_lock.as_ref()?, self.as_ref().u.interp_func_params.tF)
)?;
self.as_ref()
.u
.interp_func_params
.interpPH
.write(Handle::into_raw(interpolated));
},
ae_sys::PF_Arbitrary_COMPARE_FUNC => {
let mut handle_a = Handle::<T>::from_raw(unsafe { self.as_ref().u.compare_func_params.a_arbH }, false)?;
let handle_a_lock = handle_a.lock()?;
let a = handle_a_lock.as_ref()?;
let mut handle_b = Handle::<T>::from_raw(unsafe { self.as_ref().u.compare_func_params.b_arbH }, false)?;
let handle_b_lock = handle_b.lock()?;
let b = handle_b_lock.as_ref()?;
if a < b {
unsafe {
self.as_ref()
.u
.compare_func_params
.compareP
.write(ae_sys::PF_ArbCompare_LESS as _);
}
} else if a > b {
unsafe {
self.as_ref()
.u
.compare_func_params
.compareP
.write(ae_sys::PF_ArbCompare_MORE as _);
}
} else if a == b {
unsafe {
self.as_ref()
.u
.compare_func_params
.compareP
.write(ae_sys::PF_ArbCompare_EQUAL as _);
}
} else {
unsafe {
self.as_ref()
.u
.compare_func_params
.compareP
.write(ae_sys::PF_ArbCompare_NOT_EQUAL as _);
}
}
}
ae_sys::PF_Arbitrary_PRINT_SIZE_FUNC => unsafe {
let mut handle = Handle::<T>::from_raw(self.as_ref().u.print_size_func_params.arbH, false)?;
let lock = handle.lock()?;
let serialized = serde_json::to_string::<T>(lock.as_ref()?).map_err(|_| Error::InternalStructDamaged)?;
let cstr = std::ffi::CString::new(serialized).unwrap();
self.as_ref().u.print_size_func_params.print_sizePLu.write(
cstr.as_bytes_with_nul().len() as _,
);
},
ae_sys::PF_Arbitrary_PRINT_FUNC => unsafe {
let mut handle = Handle::<T>::from_raw(self.as_ref().u.print_func_params.arbH, false)?;
let lock = handle.lock()?;
let serialized = serde_json::to_string::<T>(lock.as_ref()?).map_err(|_| Error::InternalStructDamaged)?;
let cstr = std::ffi::CString::new(serialized).unwrap();
let cstr = cstr.as_bytes_with_nul();
if cstr.len() <= self.as_ref().u.print_func_params.print_sizeLu as _ && self.as_ref().u.print_func_params.print_flags == 0 {
std::ptr::copy_nonoverlapping(
cstr.as_ptr(),
self.as_ref().u.print_func_params.print_bufferPC as _,
cstr.len(),
);
}
}
ae_sys::PF_Arbitrary_SCAN_FUNC => unsafe {
let cstr = CStr::from_ptr(self.as_ref().u.scan_func_params.bufPC).to_str().map_err(|_| Error::InternalStructDamaged)?;
let t = serde_json::from_str::<T>(cstr).map_err(|_| Error::InternalStructDamaged)?;
let handle = Handle::<T>::new(t)?;
self.as_ref()
.u
.scan_func_params
.arbPH
.write(Handle::into_raw(handle));
},
_ => {
return Err(Error::Generic);
}
}
Ok(())
}
}
macro_rules! define_param_cast {
($name:tt, $enm:ident, $type:ty) => {
paste::item! {
pub fn [<as_ $name>]<'a>(&'a self) -> Result<$type<'a>, Error> where 'p: 'a {
match self.as_param()? {
Param::$enm(x) => Ok(x),
x => {
log::error!("Invalid param type! Requested {:?}, but the param is {:?}", stringify!($name), x);
Err(Error::InvalidParms)
}
}
}
pub fn [<as_ $name _mut>]<'a>(&'a mut self) -> Result<$type<'a>, Error> where 'p: 'a {
match self.as_param_mut()? {
Param::$enm(x) => Ok(x),
x => {
log::error!("Invalid param type! Requested {:?}, but the param is {:?}", stringify!($name), x);
Err(Error::InvalidParms)
}
}
}
}
};
}
pub enum Param<'p> {
Angle(AngleDef<'p>),
Arbitrary(ArbitraryDef<'p>),
Button(ButtonDef<'p>),
CheckBox(CheckBoxDef<'p>),
Color(ColorDef<'p>),
FloatSlider(FloatSliderDef<'p>),
Path(PathDef<'p>),
Point(PointDef<'p>),
Point3D(Point3DDef<'p>),
Popup(PopupDef<'p>),
Slider(SliderDef<'p>),
Layer(LayerDef<'p>),
Null(NullDef<'p>),
}
impl Debug for Param<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Param::Angle(_) => write!(f, "Angle"),
Param::Arbitrary(_) => write!(f, "Arbitrary"),
Param::Button(_) => write!(f, "Button"),
Param::CheckBox(_) => write!(f, "CheckBox"),
Param::Color(_) => write!(f, "Color"),
Param::FloatSlider(_) => write!(f, "FloatSlider"),
Param::Path(_) => write!(f, "Path"),
Param::Point(_) => write!(f, "Point"),
Param::Point3D(_) => write!(f, "Point3D"),
Param::Popup(_) => write!(f, "Popup"),
Param::Slider(_) => write!(f, "Slider"),
Param::Layer(_) => write!(f, "Layer"),
Param::Null(_) => write!(f, "Null"),
}
}
}
#[derive(Clone)]
pub struct ParamDef<'p> {
param_def: Ownership<'p, ae_sys::PF_ParamDef>,
checkin_on_drop: bool,
index: Option<i32>,
in_data: InData,
}
impl<'p> ParamDef<'p> {
pub fn new(in_data: InData) -> Self {
Self {
param_def: Ownership::Rust(unsafe { std::mem::zeroed() }),
checkin_on_drop: false,
in_data,
index: None,
}
}
pub fn as_ref(&self) -> &ae_sys::PF_ParamDef {
&*self.param_def
}
pub fn as_mut(&mut self) -> &mut ae_sys::PF_ParamDef {
&mut *self.param_def
}
pub fn index(&self) -> Option<i32> {
self.index
}
pub fn update_param_ui(&self) -> Result<(), Error> {
if let Some(index) = self.index {
self.in_data.effect().update_param_ui(index, self)
} else {
Err(Error::InvalidIndex)
}
}
pub fn keyframe_count(&self) -> Result<i32, Error> {
if let Some(index) = self.index {
pf::suites::ParamUtils::new()?
.keyframe_count(self.in_data.effect_ref(), index)
} else {
Err(Error::InvalidIndex)
}
}
pub fn from_raw(in_data: InData, param_def: &'p mut ae_sys::PF_ParamDef, index: Option<i32>) -> Self {
Self {
param_def: Ownership::AfterEffectsMut(param_def),
checkin_on_drop: false,
in_data,
index,
}
}
pub fn add(&mut self, index: i32) -> Result<(), Error> {
self.in_data.interact().add_param(index, &*self.param_def)?;
if index != -1 {
self.index = Some(index);
}
Ok(())
}
pub fn checkout(in_data: InData, index: i32, what_time: i32, time_step: i32, time_scale: u32, expected_type: Option<ParamType>) -> Result<Self, Error> {
let mut param_def = in_data.interact().checkout_param(index, what_time, time_step, time_scale)?;
if param_def.param_type == ae_sys::PF_Param_RESERVED {
return Err(Error::InvalidIndex);
}
if index > 0 && expected_type.is_some() {
param_def.param_type = expected_type.unwrap().into();
}
Ok(Self {
param_def: Ownership::Rust(param_def),
checkin_on_drop: true,
in_data,
index: Some(index),
})
}
pub fn set_param(&mut self, param: &Param) {
match param {
Param::Popup(pd) => {
self.param_def.u.pd = *pd.def;
self.param_def.param_type = ae_sys::PF_Param_POPUP;
}
Param::Angle(ad) => {
self.param_def.u.ad = *ad.def;
self.param_def.param_type = ae_sys::PF_Param_ANGLE;
}
Param::CheckBox(bd) => {
self.param_def.u.bd = *bd.def;
self.param_def.param_type = ae_sys::PF_Param_CHECKBOX;
}
Param::Color(cd) => {
self.param_def.u.cd = *cd.def;
self.param_def.param_type = ae_sys::PF_Param_COLOR;
}
Param::Slider(sd) => {
self.param_def.u.sd = *sd.def;
self.param_def.param_type = ae_sys::PF_Param_SLIDER;
}
Param::FloatSlider(fs_d) => {
self.param_def.u.fs_d = *fs_d.def;
self.param_def.param_type = ae_sys::PF_Param_FLOAT_SLIDER;
}
Param::Button(button_d) => {
self.param_def.u.button_d = *button_d.def;
self.param_def.param_type = ae_sys::PF_Param_BUTTON;
}
Param::Path(path_d) => {
self.param_def.u.path_d = *path_d.def;
self.param_def.param_type = ae_sys::PF_Param_PATH;
}
Param::Point(td) => {
self.param_def.u.td = *td.def;
self.param_def.param_type = ae_sys::PF_Param_POINT;
}
Param::Point3D(point3d_d) => {
self.param_def.u.point3d_d = *point3d_d.def;
self.param_def.param_type = ae_sys::PF_Param_POINT_3D;
}
Param::Arbitrary(arb_d) => {
self.param_def.u.arb_d = *arb_d.def;
self.param_def.param_type = ae_sys::PF_Param_ARBITRARY_DATA;
}
Param::Layer(ld) => {
self.param_def.u.ld = *ld.def;
self.param_def.param_type = ae_sys::PF_Param_LAYER;
}
Param::Null(_) => {
self.param_def.param_type = ae_sys::PF_Param_NO_DATA;
}
}
}
define_param_cast!("popup", Popup, PopupDef);
define_param_cast!("angle", Angle, AngleDef);
define_param_cast!("checkbox", CheckBox, CheckBoxDef);
define_param_cast!("color", Color, ColorDef);
define_param_cast!("slider", Slider, SliderDef);
define_param_cast!("float_slider", FloatSlider, FloatSliderDef);
define_param_cast!("button", Button, ButtonDef);
define_param_cast!("arbitrary", Arbitrary, ArbitraryDef);
define_param_cast!("point", Point, PointDef);
define_param_cast!("point3d", Point3D, Point3DDef);
define_param_cast!("path", Path, PathDef);
define_param_cast!("layer", Layer, LayerDef);
define_param_cast!("null", Null, NullDef);
pub fn as_param<'a>(&'a self) -> Result<Param<'a>, Error> where 'p: 'a {
let param_def = &*self.param_def;
let parent_ptr = param_def as *const _;
unsafe {
match param_def.param_type {
ae_sys::PF_Param_ANGLE => Ok(Param::Angle (AngleDef ::from_ref(¶m_def.u.ad, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_ARBITRARY_DATA => Ok(Param::Arbitrary (ArbitraryDef ::from_ref(¶m_def.u.arb_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_BUTTON => Ok(Param::Button (ButtonDef ::from_ref(¶m_def.u.button_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_CHECKBOX => Ok(Param::CheckBox (CheckBoxDef ::from_ref(¶m_def.u.bd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_COLOR => Ok(Param::Color (ColorDef ::from_ref(¶m_def.u.cd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_FLOAT_SLIDER => Ok(Param::FloatSlider(FloatSliderDef::from_ref(¶m_def.u.fs_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POPUP => Ok(Param::Popup (PopupDef ::from_ref(¶m_def.u.pd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_SLIDER => Ok(Param::Slider (SliderDef ::from_ref(¶m_def.u.sd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POINT => Ok(Param::Point (PointDef ::from_ref(¶m_def.u.td, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POINT_3D => Ok(Param::Point3D (Point3DDef ::from_ref(¶m_def.u.point3d_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_PATH => Ok(Param::Path (PathDef ::from_ref(¶m_def.u.path_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_LAYER => Ok(Param::Layer (LayerDef ::from_ref(¶m_def.u.ld, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_NO_DATA => Ok(Param::Null (NullDef ::new())),
_ => {
log::error!("Invalid parameter type: {}", param_def.param_type);
Err(Error::InvalidParms)
}
}
}
}
pub fn as_param_mut<'a>(&'a mut self) -> Result<Param<'a>, Error> where 'p: 'a {
let param_def = &mut *self.param_def;
let parent_ptr = param_def as *const _;
unsafe {
match param_def.param_type {
ae_sys::PF_Param_ANGLE => Ok(Param::Angle (AngleDef ::from_mut(&mut param_def.u.ad, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_ARBITRARY_DATA => Ok(Param::Arbitrary (ArbitraryDef ::from_mut(&mut param_def.u.arb_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_BUTTON => Ok(Param::Button (ButtonDef ::from_mut(&mut param_def.u.button_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_CHECKBOX => Ok(Param::CheckBox (CheckBoxDef ::from_mut(&mut param_def.u.bd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_COLOR => Ok(Param::Color (ColorDef ::from_mut(&mut param_def.u.cd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_FLOAT_SLIDER => Ok(Param::FloatSlider(FloatSliderDef::from_mut(&mut param_def.u.fs_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POPUP => Ok(Param::Popup (PopupDef ::from_mut(&mut param_def.u.pd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_SLIDER => Ok(Param::Slider (SliderDef ::from_mut(&mut param_def.u.sd, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POINT => Ok(Param::Point (PointDef ::from_mut(&mut param_def.u.td, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_POINT_3D => Ok(Param::Point3D (Point3DDef ::from_mut(&mut param_def.u.point3d_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_PATH => Ok(Param::Path (PathDef ::from_mut(&mut param_def.u.path_d, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_LAYER => Ok(Param::Layer (LayerDef ::from_mut(&mut param_def.u.ld, self.in_data.as_ptr(), parent_ptr))),
ae_sys::PF_Param_NO_DATA => Ok(Param::Null (NullDef ::new())),
_ => {
log::error!("Invalid parameter type: {}", param_def.param_type);
Err(Error::InvalidParms)
}
}
}
}
pub fn is_valid(&self) -> bool {
matches!(
self.param_def.param_type,
ae_sys::PF_Param_ANGLE
| ae_sys::PF_Param_ARBITRARY_DATA
| ae_sys::PF_Param_BUTTON
| ae_sys::PF_Param_CHECKBOX
| ae_sys::PF_Param_COLOR
| ae_sys::PF_Param_FIX_SLIDER
| ae_sys::PF_Param_FLOAT_SLIDER
| ae_sys::PF_Param_GROUP_START
| ae_sys::PF_Param_GROUP_END
| ae_sys::PF_Param_POPUP
| ae_sys::PF_Param_SLIDER
| ae_sys::PF_Param_POINT
| ae_sys::PF_Param_POINT_3D
| ae_sys::PF_Param_PATH
| ae_sys::PF_Param_LAYER
| ae_sys::PF_Param_NO_DATA
)
}
pub fn param_type(&self) -> ParamType {
self.param_def.param_type.into()
}
pub unsafe fn layer_def(&mut self) -> *mut ae_sys::PF_LayerDef {
unsafe { &mut self.param_def.u.ld }
}
pub fn set_name(&mut self, name: &str) -> Result<(), Error> {
if name.is_empty() {
self.param_def.name_do_not_use_directly[0] = 0;
return Ok(());
}
let mut bytes = {
#[cfg(target_os = "macos")]
unsafe {
let cfstr = CFString::from_str(name);
let encoding = CFString::system_encoding();
let length = cfstr.length();
let max_size = CFString::maximum_size_for_encoding(length, encoding);
let mut buffer = vec![0u8; max_size as usize];
let mut used_len = 0;
CFString::bytes(
&cfstr,
CFRange::new(0, length),
encoding,
b'?', false,
buffer.as_mut_ptr(),
max_size,
&mut used_len,
);
buffer.truncate(used_len as usize);
buffer
}
#[cfg(target_os = "windows")]
unsafe {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use windows_sys::Win32::Globalization::{WideCharToMultiByte, CP_OEMCP};
let mut wstr: Vec<u16> = OsStr::new(name).encode_wide().collect();
if !wstr.is_empty() {
wstr.push(0); let len = WideCharToMultiByte(CP_OEMCP, 0, wstr.as_ptr(), wstr.len() as i32, std::ptr::null_mut(), 0, std::ptr::null(), std::ptr::null_mut());
if len > 0 {
let mut bytes: Vec<u8> = Vec::with_capacity(len as usize);
let len = WideCharToMultiByte(CP_OEMCP, 0, wstr.as_ptr(), wstr.len() as i32, bytes.as_mut_ptr() as _, len, std::ptr::null(), std::ptr::null_mut());
if len > 0 {
bytes.set_len(len as usize);
bytes
} else {
Vec::new()
}
} else {
Vec::new()
}
} else {
Vec::new()
}
}
};
let to_copy = bytes.len().min(MAX_NAME_LEN);
if to_copy > 0 {
bytes.resize(to_copy, 0);
if let Some(last_elem) = bytes.get_mut(MAX_NAME_LEN - 1) {
*last_elem = 0;
}
self.param_def.name_do_not_use_directly[0..bytes.len()].copy_from_slice(unsafe { std::mem::transmute(bytes.as_slice()) });
return Ok(());
}
log::error!("Failed to set the parameter name, \"{name}\" is too long or contains invalid characters for the system encoding.");
Err(Error::InvalidParms)
}
pub fn set_flags (&mut self, f: ParamFlag) { self.param_def.flags = f.bits() as _; }
pub fn set_change_flags(&mut self, f: ChangeFlag) { self.param_def.uu.change_flags = f.bits() as _; }
pub fn set_ui_flags (&mut self, f: ParamUIFlags) { self.param_def.ui_flags = f.bits() as _; }
pub fn set_flag (&mut self, f: ParamFlag, set: bool) { let mut v = self.flags(); v.set(f, set); self.set_flags(v); }
pub fn set_change_flag(&mut self, f: ChangeFlag, set: bool) { let mut v = self.change_flags(); v.set(f, set); self.set_change_flags(v); }
pub fn set_ui_flag (&mut self, f: ParamUIFlags, set: bool) { let mut v = self.ui_flags(); v.set(f, set); self.set_ui_flags(v); }
pub fn flags (&self) -> ParamFlag { ParamFlag::from_bits_truncate(self.param_def.flags) }
pub fn change_flags(&self) -> ChangeFlag { ChangeFlag::from_bits_truncate(unsafe { self.param_def.uu.change_flags }) }
pub fn ui_flags (&self) -> ParamUIFlags { ParamUIFlags::from_bits_truncate(self.param_def.ui_flags) }
pub fn set_ui_width(&mut self, width: u16) {
self.param_def.ui_width = width as _;
}
pub fn set_ui_height(&mut self, height: u16) {
self.param_def.ui_height = height as _;
}
pub fn set_id(&mut self, id: i32) {
self.param_def.uu.id = id;
if self.param_def.param_type == ae_sys::PF_Param_ARBITRARY_DATA {
self.param_def.u.arb_d.id = id as i16; }
}
pub fn set_value_changed(&mut self) {
self.param_def.uu.change_flags = ChangeFlag::CHANGED_VALUE.bits();
}
}
impl Drop for ParamDef<'_> {
fn drop(&mut self) {
if self.checkin_on_drop {
self.in_data.interact().checkin_param(&*self.param_def).unwrap()
}
}
}
impl Debug for ParamDef<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParamDef")
.field("type", &self.param_type())
.field("checkin_on_drop", &self.checkin_on_drop)
.field("in_data_ptr", &self.in_data.as_ptr())
.finish()
}
}
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
#[derive(Clone, Debug)]
pub struct ParamMapInfo {
pub index: usize,
pub type_: ParamType,
}
impl ParamMapInfo {
fn new(index: usize, type_: ParamType) -> Self {
Self { index, type_ }
}
}
#[derive(Clone)]
pub struct Parameters<'p, P: Eq + PartialEq + Hash + Copy + Debug> {
num_params: usize,
in_data: *const ae_sys::PF_InData,
pub map: Ownership<'p, HashMap<P, ParamMapInfo>>,
params: Vec<ParamDef<'p>>,
}
impl<P: Eq + PartialEq + Hash + Copy + Debug> Default for Parameters<'_, P> {
fn default() -> Self {
Self::new()
}
}
impl<'p, P: Eq + PartialEq + Hash + Copy + Debug> Parameters<'p, P> {
pub fn len(&self) -> usize {
self.map.len()
}
pub fn set_in_data(&mut self, in_data: *const ae_sys::PF_InData) {
self.in_data = in_data;
}
pub fn in_data(&self) -> InData {
InData::from_raw(self.in_data)
}
pub fn new() -> Self {
Self {
in_data: std::ptr::null(),
num_params: 1,
map: Ownership::Rust(Default::default()),
params: Vec::new(),
}
}
pub fn with_params(in_data: *const ae_sys::PF_InData, params: &'p [*mut ae_sys::PF_ParamDef], map: Option<&'p HashMap<P, ParamMapInfo>>, num_params: usize) -> Self {
let in_data_obj = InData::from_raw(in_data);
Self {
in_data,
params: if params.is_empty() || params[0].is_null() {
Vec::new()
} else {
params
.iter()
.enumerate()
.map(|(i, p)| { debug_assert!(!p.is_null()); ParamDef::from_raw(in_data_obj, unsafe { &mut **p }, Some(i as i32)) })
.collect::<Vec<_>>()
},
num_params,
map: map.map_or_else(|| Ownership::Rust(HashMap::new()), Ownership::AfterEffects),
}
}
fn param_id(type_: P) -> i32 {
use hash32::Murmur3Hasher;
use std::hash::Hasher;
let mut hasher = Murmur3Hasher::default();
format!("{type_:?}").hash(&mut hasher);
hasher.finish() as i32
}
pub fn add_group<F: FnOnce(&mut Self) -> Result<(), Error>>(&mut self, type_start: P, type_end: P, name: &str, start_collapsed: bool, inner_cb: F) -> Result<(), Error> {
assert!(!self.in_data.is_null());
let mut param_def = ParamDef::new(InData::from_raw(self.in_data));
param_def.set_name(name)?;
param_def.as_mut().param_type = ParamType::GroupStart.into();
param_def.set_id(Self::param_id(type_start));
if start_collapsed {
param_def.set_flags(ParamFlag::START_COLLAPSED);
}
param_def.add(-1)?;
self.map.insert(type_start, ParamMapInfo::new(self.num_params, ParamType::GroupStart));
self.num_params += 1;
inner_cb(self)?;
let mut param_def = ParamDef::new(InData::from_raw(self.in_data));
param_def.as_mut().param_type = ParamType::GroupEnd.into();
param_def.set_id(Self::param_id(type_end));
param_def.add(-1)?;
self.map.insert(type_end, ParamMapInfo::new(self.num_params, ParamType::GroupEnd));
self.num_params += 1;
Ok(())
}
pub fn add<'a>(&mut self, type_: P, name: &str, def: impl Into<Param<'a>>) -> Result<(), Error> {
assert!(!self.in_data.is_null());
let param = def.into();
let mut param_def = ParamDef::new(InData::from_raw(self.in_data));
param_def.set_name(name)?;
param_def.set_param(¶m);
let param_type = param_def.param_type();
param_def.set_id(Self::param_id(type_));
if matches!(param, Param::Button(_)) {
param_def.set_flags(ParamFlag::SUPERVISE);
}
param_def.add(-1)?;
self.map.insert(type_, ParamMapInfo::new(self.num_params, param_type));
self.num_params += 1;
Ok(())
}
pub fn add_with_flags<'a>(&mut self, type_: P, name: &str, def: impl Into<Param<'a>>, flags: ParamFlag, ui_flags: ParamUIFlags) -> Result<(), Error> {
assert!(!self.in_data.is_null());
let param = def.into();
let mut param_def = ParamDef::new(InData::from_raw(self.in_data));
param_def.set_name(name)?;
param_def.set_param(¶m);
let param_type = param_def.param_type();
param_def.set_id(Self::param_id(type_));
param_def.set_flags(flags);
param_def.set_ui_flags(ui_flags);
param_def.add(-1)?;
self.map.insert(type_, ParamMapInfo::new(self.num_params, param_type));
self.num_params += 1;
Ok(())
}
pub fn add_customized<'a, F: FnOnce(&mut ParamDef) -> i32>(&mut self, type_: P, name: &str, def: impl Into<Param<'a>>, cb: F) -> Result<(), Error> {
assert!(!self.in_data.is_null());
let param = def.into();
let mut param_def = ParamDef::new(InData::from_raw(self.in_data));
param_def.set_name(name)?;
param_def.set_param(¶m);
let param_type = param_def.param_type();
param_def.set_id(Self::param_id(type_));
let mut index = cb(&mut param_def);
param_def.add(index)?;
if index == -1 {
index = self.num_params as i32;
}
self.map.insert(type_, ParamMapInfo::new(index as usize, param_type));
self.num_params += 1;
Ok(())
}
#[inline(always)]
pub fn get(&self, type_: P) -> Result<ReadOnlyOwnership<'_, ParamDef<'p>>, Error> {
self.get_at(type_, None, None, None)
}
#[inline(always)]
pub fn get_mut(&mut self, type_: P) -> Result<Ownership<'_, ParamDef<'p>>, Error> {
self.get_mut_at(type_, None, None, None)
}
#[inline(always)]
pub fn checkout(&self, type_: P) -> Result<Ownership<'_, ParamDef<'p>>, Error> {
self.checkout_at(type_, None, None, None)
}
pub fn get_at(&self, type_: P, time: Option<i32>, time_step: Option<i32>, time_scale: Option<u32>) -> Result<ReadOnlyOwnership<'_, ParamDef<'p>>, Error> {
if self.params.is_empty() || time.is_some() {
match self.checkout_at(type_, time, time_step, time_scale) {
Ok(Ownership::Rust(param)) => Ok(ReadOnlyOwnership::Rust(param)),
Ok(_) => unreachable!(),
Err(e) => Err(e)
}
} else {
let index = self.index(type_).ok_or(Error::InvalidIndex)?;
Ok(ReadOnlyOwnership::AfterEffects(self.params.get(index).ok_or(Error::InvalidIndex)?))
}
}
pub fn get_mut_at(&mut self, type_: P, time: Option<i32>, time_step: Option<i32>, time_scale: Option<u32>) -> Result<Ownership<'_, ParamDef<'p>>, Error> {
if self.params.is_empty() || time.is_some() {
self.checkout_at(type_, time, time_step, time_scale)
} else {
let index = self.index(type_).ok_or(Error::InvalidIndex)?;
Ok(Ownership::AfterEffectsMut(self.params.get_mut(index).ok_or(Error::InvalidIndex)?))
}
}
pub fn checkout_at(&self, type_: P, time: Option<i32>, time_step: Option<i32>, time_scale: Option<u32>) -> Result<Ownership<'_, ParamDef<'p>>, Error> {
let index = self.index(type_).ok_or(Error::InvalidIndex)?;
let type_ = self.raw_param_type(type_).ok_or(Error::InvalidIndex)?;
let in_data = self.in_data();
let param = ParamDef::checkout(
in_data,
index as i32,
time.unwrap_or(in_data.current_time()),
time_step.unwrap_or(in_data.time_step()),
time_scale.unwrap_or(in_data.time_scale()),
Some(type_)
)?;
if !param.is_valid() {
return Err(Error::InvalidParms);
}
Ok(Ownership::Rust(param))
}
pub fn num_params(&self) -> usize {
self.num_params
}
pub fn index(&self, type_: P) -> Option<usize> {
self.map.get(&type_).map(|x| x.index)
}
pub fn type_at(&self, index: usize) -> P {
*self.map.iter().find(|(_, v)| v.index == index).unwrap().0
}
pub fn raw_params(&self) -> &[ParamDef<'p>] {
&self.params
}
pub fn raw_param_type(&self, type_: P) -> Option<ParamType> {
self.map.get(&type_).map(|x| x.type_)
}
pub fn cloned(&self) -> Parameters<'p, P> {
Parameters::<'p, P> {
in_data: self.in_data,
num_params: self.num_params,
map: self.map.clone(),
params: self.params.to_vec(),
}
}
}