use super::*;
use bacnet_services::read_range::{
ReadRangeAck, ReadRangeReply, ReadRangeRequest, ReadRangeValidation,
};
use bacnet_services::rpm::{ReadPropertyMultipleACK, ReadPropertyMultipleRequest};
use bacnet_types::enums::{ErrorClass, ErrorCode, ObjectType};
#[doc(hidden)]
#[derive(Clone)]
pub enum EndpointReadRequest {
Property(ReadPropertyRequest),
Range(ReadRangeRequest, ReadRangeValidation),
Multiple(ReadPropertyMultipleRequest),
}
#[doc(hidden)]
#[derive(Debug)]
pub enum EndpointReadAck {
Property(ReadPropertyACK),
Range(ReadRangeReply),
Multiple(ReadPropertyMultipleACK),
}
impl EndpointReadRequest {
#[doc(hidden)]
pub fn validate(&self) -> Result<(), Error> {
if let Self::Multiple(request) = self {
crate::endpoint_rpm::validate_request(request)?;
}
Ok(())
}
#[doc(hidden)]
pub fn identities(&self) -> Vec<(ObjectIdentifier, PropertyIdentifier, Option<u32>)> {
match self {
Self::Property(r) => vec![(
r.object_identifier,
r.property_identifier,
r.property_array_index,
)],
Self::Range(r, _) => vec![(
r.object_identifier,
r.property_identifier,
r.property_array_index,
)],
Self::Multiple(r) => r
.list_of_read_access_specs
.iter()
.flat_map(|s| {
s.list_of_property_references.iter().map(|p| {
(
s.object_identifier,
p.property_identifier,
p.property_array_index,
)
})
})
.collect(),
}
}
pub(super) fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
self.validate()?;
match self {
Self::Property(r) => {
r.encode(buf);
Ok(())
}
Self::Range(r, _) => r.encode(buf),
Self::Multiple(r) => r.encode(buf),
}
}
pub(super) fn service(&self) -> ConfirmedServiceChoice {
match self {
Self::Property(_) => ConfirmedServiceChoice::READ_PROPERTY,
Self::Range(..) => ConfirmedServiceChoice::READ_RANGE,
Self::Multiple(_) => ConfirmedServiceChoice::READ_PROPERTY_MULTIPLE,
}
}
pub(super) fn decode(&self, bytes: &[u8]) -> Result<EndpointReadAck, Error> {
match self {
Self::Property(request) => {
crate::read_property::decode_ack(request, bytes).map(EndpointReadAck::Property)
}
Self::Multiple(request) => {
crate::endpoint_rpm::decode_ack(request, bytes).map(EndpointReadAck::Multiple)
}
Self::Range(request, validation) => {
ReadRangeReply::check(request, ReadRangeAck::decode(bytes)?, *validation)
.map(EndpointReadAck::Range)
}
}
}
}
impl EndpointReadAck {
#[doc(hidden)]
pub fn audit_results(&self) -> Vec<(ObjectIdentifier, Option<(ErrorClass, ErrorCode)>)> {
match self {
Self::Property(ack) => vec![(ack.object_identifier, None)],
Self::Range(reply) => vec![(reply.ack.object_identifier, None)],
Self::Multiple(ack) => ack
.list_of_read_access_results
.iter()
.flat_map(|s| {
s.list_of_results
.iter()
.map(|p| (s.object_identifier, p.error))
})
.collect(),
}
}
#[doc(hidden)]
pub fn target_device(&self) -> Option<ObjectIdentifier> {
let mut devices = self
.audit_results()
.into_iter()
.filter_map(|(object, error)| {
(error.is_none()
&& object.object_type() == ObjectType::DEVICE
&& object.instance_number() != ObjectIdentifier::WILDCARD_INSTANCE)
.then_some(object)
});
let first = devices.next()?;
devices.all(|object| object == first).then_some(first)
}
#[doc(hidden)]
pub fn into_multiple(self) -> Result<ReadPropertyMultipleACK, Error> {
match self {
Self::Multiple(ack) => Ok(ack),
_ => Err(Error::Encoding("endpoint read result kind mismatch".into())),
}
}
#[doc(hidden)]
pub fn into_property(self) -> Result<ReadPropertyACK, Error> {
match self {
Self::Property(ack) => Ok(ack),
_ => Err(Error::Encoding("endpoint read result kind mismatch".into())),
}
}
#[doc(hidden)]
pub fn into_range(self) -> Result<ReadRangeReply, Error> {
match self {
Self::Range(reply) => Ok(reply),
_ => Err(Error::Encoding("endpoint read result kind mismatch".into())),
}
}
}