use crate::Time;
use fuchsia_zircon_sys as sys;
use std::fmt::Debug;
pub trait State {
fn add_args(&self, args: &mut sys::zx_clock_update_args_v2_t);
fn add_options(&self, options: &mut u64);
}
pub trait ValueState: State {}
pub trait RateState: State {}
pub trait ErrorState: State {}
pub struct Null;
impl State for Null {
fn add_args(&self, _: &mut sys::zx_clock_update_args_v2_t) {}
fn add_options(&self, _: &mut u64) {}
}
impl ValueState for Null {}
impl RateState for Null {}
impl ErrorState for Null {}
pub struct AbsoluteValue {
reference_value: Time,
synthetic_value: Time,
}
impl State for AbsoluteValue {
#[inline]
fn add_args(&self, args: &mut sys::zx_clock_update_args_v2_t) {
args.reference_value = self.reference_value.into_nanos();
args.synthetic_value = self.synthetic_value.into_nanos();
}
#[inline]
fn add_options(&self, opts: &mut u64) {
*opts |= sys::ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID
| sys::ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID;
}
}
impl ValueState for AbsoluteValue {}
pub struct ApproximateValue(Time);
impl State for ApproximateValue {
#[inline]
fn add_args(&self, args: &mut sys::zx_clock_update_args_v2_t) {
args.synthetic_value = self.0.into_nanos();
}
#[inline]
fn add_options(&self, opts: &mut u64) {
*opts |= sys::ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID;
}
}
impl ValueState for ApproximateValue {}
pub struct Rate(i32);
impl State for Rate {
#[inline]
fn add_args(&self, args: &mut sys::zx_clock_update_args_v2_t) {
args.rate_adjust = self.0;
}
#[inline]
fn add_options(&self, opts: &mut u64) {
*opts |= sys::ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID;
}
}
impl RateState for Rate {}
pub struct Error(u64);
impl State for Error {
#[inline]
fn add_args(&self, args: &mut sys::zx_clock_update_args_v2_t) {
args.error_bound = self.0;
}
#[inline]
fn add_options(&self, opts: &mut u64) {
*opts |= sys::ZX_CLOCK_UPDATE_OPTION_ERROR_BOUND_VALID;
}
}
impl ErrorState for Error {}
#[derive(Debug, Eq, PartialEq)]
pub struct ClockUpdateBuilder<V: ValueState, R: RateState, E: ErrorState> {
value_state: V,
rate_state: R,
error_state: E,
}
impl<V: ValueState, R: RateState, E: ErrorState> ClockUpdateBuilder<V, R, E> {
#[inline]
pub fn build(self) -> ClockUpdate {
ClockUpdate::from(self)
}
}
impl ClockUpdateBuilder<Null, Null, Null> {
#[inline]
fn new() -> Self {
Self { value_state: Null, rate_state: Null, error_state: Null }
}
}
impl<R: RateState, E: ErrorState> ClockUpdateBuilder<Null, R, E> {
#[inline]
pub fn absolute_value(
self,
reference_value: Time,
synthetic_value: Time,
) -> ClockUpdateBuilder<AbsoluteValue, R, E> {
ClockUpdateBuilder {
value_state: AbsoluteValue { reference_value, synthetic_value },
rate_state: self.rate_state,
error_state: self.error_state,
}
}
}
impl<E: ErrorState> ClockUpdateBuilder<Null, Null, E> {
#[inline]
pub fn approximate_value(
self,
synthetic_value: Time,
) -> ClockUpdateBuilder<ApproximateValue, Null, E> {
ClockUpdateBuilder {
value_state: ApproximateValue(synthetic_value),
rate_state: self.rate_state,
error_state: self.error_state,
}
}
}
impl<E: ErrorState> ClockUpdateBuilder<Null, Null, E> {
#[inline]
pub fn rate_adjust(self, rate_adjust_ppm: i32) -> ClockUpdateBuilder<Null, Rate, E> {
ClockUpdateBuilder {
value_state: self.value_state,
rate_state: Rate(rate_adjust_ppm),
error_state: self.error_state,
}
}
}
impl<E: ErrorState> ClockUpdateBuilder<AbsoluteValue, Null, E> {
#[inline]
pub fn rate_adjust(self, rate_adjust_ppm: i32) -> ClockUpdateBuilder<AbsoluteValue, Rate, E> {
ClockUpdateBuilder {
value_state: self.value_state,
rate_state: Rate(rate_adjust_ppm),
error_state: self.error_state,
}
}
}
impl<V: ValueState, R: RateState> ClockUpdateBuilder<V, R, Null> {
#[inline]
pub fn error_bounds(self, error_bound_ns: u64) -> ClockUpdateBuilder<V, R, Error> {
ClockUpdateBuilder {
value_state: self.value_state,
rate_state: self.rate_state,
error_state: Error(error_bound_ns),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ClockUpdate {
options: u64,
args: sys::zx_clock_update_args_v2_t,
}
impl ClockUpdate {
#[inline]
pub fn builder() -> ClockUpdateBuilder<Null, Null, Null> {
ClockUpdateBuilder::new()
}
#[inline]
pub fn options(&self) -> u64 {
self.options
}
}
impl<V: ValueState, R: RateState, E: ErrorState> From<ClockUpdateBuilder<V, R, E>> for ClockUpdate {
fn from(builder: ClockUpdateBuilder<V, R, E>) -> Self {
let mut args = sys::zx_clock_update_args_v2_t::default();
builder.value_state.add_args(&mut args);
builder.rate_state.add_args(&mut args);
builder.error_state.add_args(&mut args);
let mut options = sys::ZX_CLOCK_ARGS_VERSION_2;
builder.value_state.add_options(&mut options);
builder.rate_state.add_options(&mut options);
builder.error_state.add_options(&mut options);
Self { options, args }
}
}
impl From<ClockUpdate> for sys::zx_clock_update_args_v2_t {
fn from(clock_update: ClockUpdate) -> Self {
clock_update.args
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_update() {
let update = ClockUpdateBuilder::new().build();
assert_eq!(update.options(), sys::ZX_CLOCK_ARGS_VERSION_2);
assert_eq!(
sys::zx_clock_update_args_v2_t::from(update),
sys::zx_clock_update_args_v2_t {
rate_adjust: 0,
padding1: Default::default(),
reference_value: 0,
synthetic_value: 0,
error_bound: 0,
}
);
}
#[test]
fn rate_only() {
let update = ClockUpdate::from(ClockUpdateBuilder::new().rate_adjust(52));
assert_eq!(
update.options(),
sys::ZX_CLOCK_ARGS_VERSION_2 | sys::ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID
);
assert_eq!(
sys::zx_clock_update_args_v2_t::from(update),
sys::zx_clock_update_args_v2_t {
rate_adjust: 52,
padding1: Default::default(),
reference_value: 0,
synthetic_value: 0,
error_bound: 0,
}
);
}
#[test]
fn approximate_value() {
let update = ClockUpdateBuilder::new()
.approximate_value(Time::from_nanos(42))
.error_bounds(62)
.build();
assert_eq!(
update.options(),
sys::ZX_CLOCK_ARGS_VERSION_2
| sys::ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID
| sys::ZX_CLOCK_UPDATE_OPTION_ERROR_BOUND_VALID
);
assert_eq!(
sys::zx_clock_update_args_v2_t::from(update),
sys::zx_clock_update_args_v2_t {
rate_adjust: 0,
padding1: Default::default(),
reference_value: 0,
synthetic_value: 42,
error_bound: 62,
}
);
}
#[test]
fn absolute_value() {
let update = ClockUpdateBuilder::new()
.absolute_value(Time::from_nanos(1000), Time::from_nanos(42))
.rate_adjust(52)
.error_bounds(62)
.build();
assert_eq!(
update.options(),
sys::ZX_CLOCK_ARGS_VERSION_2
| sys::ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID
| sys::ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID
| sys::ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID
| sys::ZX_CLOCK_UPDATE_OPTION_ERROR_BOUND_VALID
);
assert_eq!(
sys::zx_clock_update_args_v2_t::from(update),
sys::zx_clock_update_args_v2_t {
rate_adjust: 52,
padding1: Default::default(),
reference_value: 1000,
synthetic_value: 42,
error_bound: 62,
}
);
}
}