use std::ops::RangeInclusive;
use std::time::Duration;
use bacnet_types::constructed::BACnetXyColor;
use bacnet_types::enums::ColorTransition;
use bacnet_types::error::Error;
use bacnet_types::primitives::PropertyValue;
use crate::audit::ObjectAuditPolicy;
use crate::common;
mod command;
mod engine;
mod metadata;
mod temperature;
mod xy;
pub use temperature::ColorTemperatureObject;
pub use xy::ColorObject;
#[cfg(test)]
mod command_tests;
#[cfg(test)]
mod engine_tests;
#[cfg(test)]
mod metadata_tests;
#[cfg(test)]
mod rows_tests;
#[cfg(test)]
mod value_source_tests;
fn xy_value(color: BACnetXyColor) -> PropertyValue {
PropertyValue::List(vec![
PropertyValue::Real(color.x),
PropertyValue::Real(color.y),
])
}
fn written_xy(value: PropertyValue) -> Result<BACnetXyColor, Error> {
let PropertyValue::List(items) = value else {
return Err(common::invalid_data_type_error());
};
let [PropertyValue::Real(x), PropertyValue::Real(y)] = items.as_slice() else {
return Err(common::invalid_data_type_error());
};
let color = BACnetXyColor::new(*x, *y);
if command::xy_in_range(color) {
Ok(color)
} else {
Err(common::value_out_of_range_error())
}
}
fn written_unsigned(value: PropertyValue, range: RangeInclusive<u32>) -> Result<u32, Error> {
let PropertyValue::Unsigned(value) = value else {
return Err(common::invalid_data_type_error());
};
u32::try_from(value)
.ok()
.filter(|value| range.contains(value))
.ok_or_else(common::value_out_of_range_error)
}
fn written_transition(
value: PropertyValue,
last: ColorTransition,
) -> Result<ColorTransition, Error> {
let PropertyValue::Enumerated(raw) = value else {
return Err(common::invalid_data_type_error());
};
if raw > last.to_raw() {
return Err(common::value_out_of_range_error());
}
Ok(ColorTransition::from_raw(raw))
}
fn noncommandable_audit_policy(policy: ObjectAuditPolicy) -> ObjectAuditPolicy {
ObjectAuditPolicy {
priority_filter: None,
..policy
}
}
fn milliseconds(fade_time: u32) -> Duration {
Duration::from_millis(u64::from(fade_time))
}