use alloc::format;
use alloc::vec::Vec;
use core::marker::PhantomData;
use super::{Container, CriticalityOf, Field, Message, Pdu, Protocol};
use crate::{Encode, Error, ErrorKind, Octets, Writer};
#[doc(hidden)]
pub fn __ie<P: Protocol, T: Encode>(
id: u16,
criticality: CriticalityOf<P>,
value: &T,
) -> Result<P::Field<'static>, Error> {
let octets = crate::encode(value).map(Octets::owned)?;
Ok(P::Field::__new(id, criticality, octets))
}
fn assigned<'a, M: Container<'a>>(
id: u16,
name: &str,
) -> Result<CriticalityOf<M::Protocol>, Error> {
M::__assigned(id).map(Into::into).ok_or_else(|| {
let why = format!(
"{name} is no IE of the object set of {}, which assigns it no criticality: write \
its criticality",
M::NAME
);
Error::new(ErrorKind::Argument, why)
})
}
#[doc(hidden)]
pub fn __assigned_ie<'a, M: Container<'a>, T: Encode>(
id: u16,
name: &str,
value: &T,
) -> Result<<M::Protocol as Protocol>::Field<'static>, Error> {
__ie::<M::Protocol, T>(id, assigned::<M>(id, name)?, value)
}
#[doc(hidden)]
pub struct __Message<P: Protocol> {
octets: Vec<u8>,
count: usize,
error: Option<Error>,
protocol: PhantomData<P>,
}
impl<P: Protocol> __Message<P> {
#[doc(hidden)]
#[allow(clippy::new_without_default)]
#[inline]
pub fn new() -> Self {
let mut octets = Vec::with_capacity(256);
octets.extend_from_slice(&[0, 0, 0]);
Self {
octets,
count: 0,
error: None,
protocol: PhantomData,
}
}
#[doc(hidden)]
#[inline]
pub fn ie<T: Encode>(&mut self, id: u16, criticality: CriticalityOf<P>, value: &T) {
if self.error.is_some() {
return;
}
let start = self.octets.len();
let criticality: crate::Criticality = criticality.into();
let mut writer = Writer::new(&mut self.octets);
writer.octets(&id.to_be_bytes());
writer.index(criticality as u64, 3, false);
let value_start = writer.begin_open_type();
match value.encode(&mut writer) {
Ok(()) => {
writer.end_open_type(value_start);
self.count += 1;
}
Err(error) => {
self.octets.truncate(start);
self.error = Some(error.encoding(T::NAME));
}
}
}
#[doc(hidden)]
#[inline]
pub fn ie_assigned<'a, M: Container<'a, Protocol = P>, T: Encode>(
&mut self,
id: u16,
name: &str,
value: &T,
) {
if self.error.is_some() {
return;
}
match assigned::<M>(id, name) {
Ok(criticality) => self.ie(id, criticality, value),
Err(error) => self.error = Some(error),
}
}
#[doc(hidden)]
pub fn pdu<'a, M: Message<'a, Protocol = P>>(
mut self,
criticality: CriticalityOf<P>,
) -> Result<P::Pdu<'static>, Error> {
if let Some(error) = self.error {
return Err(error);
}
let Ok(count) = u16::try_from(self.count) else {
let size = Error::new(ErrorKind::Encode, "the value does not encode").because(format!(
"a size of {} is outside its constraint (0..65535)",
self.count
));
return Err(size.of_protocol_ies(self.count));
};
self.octets[1..3].copy_from_slice(&count.to_be_bytes());
let value = Octets::owned(self.octets);
<P::Pdu<'static> as Pdu<'static>>::__of(M::DIRECTION, M::PROCEDURE_CODE, criticality, value)
.ok_or_else(|| Error::new(ErrorKind::Encode, "a message has no direction"))
}
}
#[doc(hidden)]
#[inline]
pub fn __message_of_protocol_ies<'a, M: Container<'a>>() {
const {
assert!(
M::__OF_PROTOCOL_IES,
"the message has private IEs, and no container of protocol IEs"
)
};
}
#[doc(hidden)]
#[inline]
pub fn __message_of<M, Q>(_: fn(M) -> Q) {}