mod build;
mod errors;
mod inspection;
mod macros;
mod pdu;
mod read;
pub use build::{__Message, __assigned_ie, __ie, __message_of, __message_of_protocol_ies};
pub use errors::{__missing_ie, __undecodable_ie, __wrong_message, ie_name};
pub use pdu::{
check, check_structure, check_transfer, check_transfer_structure, holds_key, message_octets,
message_octets_as_its_type, of_message, protocol_ies, set_protocol_ies,
};
pub use read::{
__Decoded, __Each, __Entry, __Fields, __Holds, __Item, __Source, __Walk, __first, __pdu_holds,
Ies, Items, Source, items_of_fields,
};
use crate::check::Diagnostics;
use crate::{AsnType, Criticality, Decode, Encode, Error, Faults, Octets};
pub type CriticalityOf<P> = <P as Diagnostics>::Criticality;
pub trait Protocol: Diagnostics + Copy + core::fmt::Debug + 'static {
const NAME: &'static str;
type Pdu<'a>: Pdu<'a, Protocol = Self>;
type Field<'a>: Field<'a, Protocol = Self>;
#[doc(hidden)]
const __OBJECT_SETS: &'static [ObjectSet<CriticalityOf<Self>>];
#[doc(hidden)]
const __OBJECT_SET_INDEX: &'static [[u16; 256]; 3];
#[doc(hidden)]
const __IE_NAMES: &'static [(u16, &'static str)];
#[doc(hidden)]
const __KEY_IES: &'static [u16];
#[doc(hidden)]
#[allow(clippy::type_complexity)]
fn __decodes(id: u16, octets: &[u8]) -> Option<Result<(Option<Error>, Faults), Error>>;
#[doc(hidden)]
fn __procedure_criticality(code: u8) -> Option<CriticalityOf<Self>>;
}
#[doc(hidden)]
#[derive(Debug)]
pub struct ObjectSet<C: 'static> {
pub direction: &'static str,
pub procedure_code: u8,
pub name: &'static str,
pub ies: Option<&'static [(u16, C, bool)]>,
}
#[doc(hidden)]
pub fn object_set<P: Protocol>(
direction: &str,
code: u8,
) -> Option<&'static ObjectSet<CriticalityOf<P>>> {
let at = P::__OBJECT_SET_INDEX[usize::from(rank(direction)?)][usize::from(code)];
let set = P::__OBJECT_SETS.get(usize::from(at))?;
(set.direction == direction).then_some(set)
}
#[inline]
const fn rank(direction: &str) -> Option<u8> {
match direction.as_bytes() {
[b'I', ..] => Some(0),
[b'S', ..] => Some(1),
[b'U', ..] => Some(2),
_ => None,
}
}
#[doc(hidden)]
pub const fn __object_set_index<C>(sets: &[ObjectSet<C>]) -> [[u16; 256]; 3] {
let mut index = [[u16::MAX; 256]; 3];
let mut at = 0;
while at < sets.len() {
let set = &sets[at];
if let Some(rank) = rank(set.direction) {
index[rank as usize][set.procedure_code as usize] = at as u16;
}
at += 1;
}
index
}
#[doc(hidden)]
pub fn name<P: Protocol>(id: u16) -> Option<&'static str> {
let names = P::__IE_NAMES;
let at = names.binary_search_by_key(&id, |(known, _)| *known);
at.ok().map(|at| names[at].1)
}
pub trait InProtocol {
type Protocol: Protocol;
}
#[doc(hidden)]
pub fn __assigned<P: Protocol>(direction: &str, code: u8, id: u16) -> Option<Criticality> {
__assigned_in(object_set::<P>(direction, code)?.ies?, id)
}
#[doc(hidden)]
#[inline]
pub fn __assigned_in<C: Copy + Into<Criticality>>(
ies: &[(u16, C, bool)],
id: u16,
) -> Option<Criticality> {
let found = ies.iter().find(|(known, ..)| *known == id);
found.map(|(_, assigned, _)| (*assigned).into())
}
#[doc(hidden)]
pub fn __type_name(path: &'static str) -> &'static str {
let name = path.rsplit(':').next().unwrap_or(path);
name.split('<').next().unwrap_or(name).trim()
}
pub trait Pdu<'a>: Decode<'a> + Encode + InProtocol + Sized {
fn direction(&self) -> &'static str;
fn procedure_code(&self) -> u8;
fn criticality(&self) -> CriticalityOf<Self::Protocol>;
fn value(&self) -> &Octets<'a>;
#[doc(hidden)]
fn __set_value(&mut self, value: Octets<'a>);
#[doc(hidden)]
fn __of(
direction: &str,
procedure_code: u8,
criticality: CriticalityOf<Self::Protocol>,
value: Octets<'a>,
) -> Option<Self>;
}
pub trait Field<'a>: Decode<'a> + Encode + InProtocol + Clone {
fn id(&self) -> u16;
fn criticality(&self) -> CriticalityOf<Self::Protocol>;
fn value(&self) -> &Octets<'a>;
#[doc(hidden)]
fn __new(id: u16, criticality: CriticalityOf<Self::Protocol>, value: Octets<'a>) -> Self;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is no container of protocol IEs",
label = "the type of a message, or of a transfer of protocol IEs, is expected here",
note = "the macros take the type of a message, as `UEContextReleaseRequest`, or of a \
transfer of protocol IEs; an IE of a list of single containers is built without \
the name of a type"
)]
pub trait Container<'a>: Decode<'a> + Encode + AsnType + InProtocol {
#[doc(hidden)]
const __OF_PROTOCOL_IES: bool;
#[doc(hidden)]
fn __assigned(id: u16) -> Option<Criticality>;
#[doc(hidden)]
fn __fields<'s>(&'s self) -> &'s [<Self::Protocol as Protocol>::Field<'s>];
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is no message of the protocol",
label = "the type of a message is expected here",
note = "a message is the type of what a PDU holds, as `UEContextReleaseRequest`; an IE of a \
list of single containers is built without the name of a type"
)]
pub trait Message<'a>: Container<'a> {
const DIRECTION: &'static str;
const PROCEDURE_CODE: u8;
const CRITICALITY: CriticalityOf<Self::Protocol>;
#[doc(hidden)]
fn __decode_owned(octets: &[u8]) -> Result<Self, Error>;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is no transfer of protocol IEs",
label = "the type of a transfer of protocol IEs is expected here",
note = "a transfer of protocol IEs is the type of octets that hold a container of protocol \
IEs, as `PDUSessionResourceSetupRequestTransfer` of NGAP"
)]
pub trait Transfer<'a>: Container<'a> {
#[doc(hidden)]
const __OBJECT_SET: &'static [(u16, CriticalityOf<Self::Protocol>, bool)];
}
pub trait Ie: Copy + core::fmt::Debug + 'static {
type Protocol: Protocol;
const ID: u16;
const NAME: &'static str;
type Value<'a>: Decode<'a> + Encode;
#[inline]
fn value<'a>(value: impl Into<Self::Value<'a>>) -> Self::Value<'a> {
value.into()
}
#[doc(hidden)]
#[allow(clippy::needless_lifetimes)]
fn __owned<'a, 'b>(octets: &'a [u8]) -> Result<Self::Value<'b>, Error>;
}
pub trait List: Ie {
type Item: Ie<Protocol = Self::Protocol>;
#[doc(hidden)]
const __SIZE: (usize, usize);
}
#[doc(hidden)]
pub trait __IntoOwned: Sized {
#[inline]
fn into_owned(self) -> Self {
self
}
}
impl<T> __IntoOwned for T {}
#[diagnostic::on_unimplemented(
message = "a field of the type `{T}` does not take the value of this IE, which is a `{Self}`",
label = "the value of the IE is a `{Self}`",
note = "declare the field as `{Self}`, or as the type of the one value that a `{Self}` holds, \
or write `=> expression` after the IE to make the field of its value"
)]
#[doc(hidden)]
pub trait __Field<T> {
fn __field(self) -> T;
}
impl<T> __Field<T> for T {
#[inline]
fn __field(self) -> T {
self
}
}