use crate::*;
#[derive(Clone, Copy, Debug, Default)]
pub enum DurationLimit {
#[default]
Configured,
Maximum(Duration),
Unlimited,
}
impl DurationLimit {
pub(crate) fn native(self) -> Result<u64> {
match self {
Self::Configured => Ok(0),
Self::Maximum(d) => millis(d),
Self::Unlimited => Ok(u64::MAX),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub enum StepLimit {
#[default]
Configured,
Maximum(f64),
Unlimited,
}
impl StepLimit {
pub(crate) fn native(self) -> Result<f64> {
match self {
Self::Configured => Ok(0.0),
Self::Unlimited => Ok(-1.0),
Self::Maximum(v) if v.is_finite() && v > 0.0 => Ok(v),
_ => Err(invalid("Step limit must be finite and positive")),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct WaitOptions {
pub policy: Wait,
pub convergence_tolerance: Option<f64>,
pub settle_time: Duration,
pub max_state_age: DurationLimit,
pub wait_ceiling: DurationLimit,
}
impl From<Wait> for WaitOptions {
fn from(policy: Wait) -> Self {
Self {
policy,
..Default::default()
}
}
}
impl WaitOptions {
pub(crate) fn native(self) -> Result<ffi::dex_wait_policy_t> {
let mut n = self.policy.native()?;
if let Some(v) = self.convergence_tolerance {
if !v.is_finite() || v <= 0.0 {
return Err(invalid("Convergence tolerance must be finite and positive"));
}
n.convergence_tolerance = v;
}
n.settle_time_ms = duration_ms(self.settle_time)?;
n.max_state_age_ms = self.max_state_age.native()?;
n.wait_ceiling_ms = self.wait_ceiling.native()?;
Ok(n)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct CommandOptions {
pub relative: bool,
pub disable_limit_enforcement: bool,
pub max_step: StepLimit,
}
impl CommandOptions {
pub(crate) fn native(self) -> Result<ffi::dex_command_options_t> {
let mut n = ffi::dex_command_options_t::default();
unsafe { ffi::dex_command_options_init(&mut n) };
n.relative = self.relative.into();
n.disable_limit_enforcement = self.disable_limit_enforcement.into();
n.max_step_rad = self.max_step.native()?;
Ok(n)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct TrajectoryOptions {
pub max_tracking_error: Option<f64>,
pub max_state_age: DurationLimit,
pub max_step: StepLimit,
}
impl TrajectoryOptions {
pub(crate) fn native(self) -> Result<ffi::dex_trajectory_options_t> {
let mut n = ffi::dex_trajectory_options_t::default();
unsafe { ffi::dex_trajectory_options_init(&mut n) };
if let Some(v) = self.max_tracking_error {
if !v.is_finite() || v < 0.0 {
return Err(invalid("Tracking error must be finite and non-negative"));
}
n.max_tracking_error = v;
}
n.max_state_age_ms = self.max_state_age.native()?;
n.max_step_rad = self.max_step.native()?;
Ok(n)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct ChassisOptions {
pub disable_sequential_steering: bool,
pub steering_tolerance: Option<f64>,
pub steering_wait: Option<Duration>,
pub max_state_age: DurationLimit,
}
impl ChassisOptions {
pub(crate) fn native(self) -> Result<ffi::dex_chassis_options_t> {
let mut n = ffi::dex_chassis_options_t::default();
unsafe { ffi::dex_chassis_options_init(&mut n) };
n.disable_sequential_steering = self.disable_sequential_steering.into();
if let Some(v) = self.steering_tolerance {
if !v.is_finite() || v <= 0.0 {
return Err(invalid("Steering tolerance must be finite and positive"));
}
n.steering_tolerance = v;
}
n.steering_wait_ms = self.steering_wait.map(millis).transpose()?.unwrap_or(0);
n.max_state_age_ms = self.max_state_age.native()?;
Ok(n)
}
}
pub(crate) fn duration_ms(d: Duration) -> Result<u64> {
let n = u64::try_from(d.as_millis()).map_err(|_| invalid("Duration is too large"))?;
if n == u64::MAX || (!d.is_zero() && n == 0) {
return Err(invalid(
"Duration must be zero or at least 1 ms and below u64::MAX ms",
));
}
Ok(n)
}