use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use oxirush_utils::tree::{self, Edit, Family, Key, Listed, Next, Place, Root, Step};
use oxirush_utils::tree::{Map, Value};
use super::views::LOSSY;
use super::{Kind, Member, Protocol, Sent, Shape, same_name, type_name};
use crate::{Error, ErrorKind};
const MESSAGE: &str = "message";
const IES: &str = "protocolIEs";
pub const EDITED: &str = "_edited";
const VALUES: [&str; 3] = ["value", "extensionValue", "decoded"];
const WRITTEN: usize = 256;
const KINDS: [ErrorKind; 16] = [
ErrorKind::Decode,
ErrorKind::Encode,
ErrorKind::WrongMessage,
ErrorKind::MissingIe,
ErrorKind::UndecodableIe,
ErrorKind::Argument,
ErrorKind::UnknownMessage,
ErrorKind::UnknownIe,
ErrorKind::Path,
ErrorKind::NoSuchMember,
ErrorKind::NothingSelected,
ErrorKind::NotOpened,
ErrorKind::Value,
ErrorKind::Form,
ErrorKind::Edit,
ErrorKind::Limit,
];
fn code(kind: ErrorKind) -> u16 {
let at = KINDS.iter().position(|known| *known == kind);
at.map_or(u16::MAX, |at| at as u16)
}
fn fault(kind: ErrorKind, reason: impl Into<String>) -> tree::Error {
let engine = match kind {
ErrorKind::Path => tree::ErrorKind::Path,
ErrorKind::Limit => tree::ErrorKind::Limit,
_ => tree::ErrorKind::NoSuchMember,
};
tree::Error::new(engine, "", reason).with_code(code(kind))
}
fn refusal(kind: ErrorKind, reason: impl Into<String>) -> tree::Error {
tree::Error::new(tree::ErrorKind::Refused, "", reason).with_code(code(kind))
}
fn reworded(error: tree::Error, reword: impl FnOnce(&str) -> String) -> tree::Error {
let again = tree::Error::new(error.kind(), error.at(), reword(error.reason()));
match error.code() {
Some(code) => again.with_code(code),
None => again,
}
}
fn error(error: tree::Error) -> Error {
let kind = match error.code() {
Some(code) => KINDS.get(usize::from(code)).copied(),
None => None,
};
let kind = kind.unwrap_or(match error.kind() {
tree::ErrorKind::Path => ErrorKind::Path,
tree::ErrorKind::Limit => ErrorKind::Limit,
tree::ErrorKind::NothingSelected => ErrorKind::NothingSelected,
tree::ErrorKind::Value => ErrorKind::Value,
tree::ErrorKind::Refused => ErrorKind::Edit,
_ => ErrorKind::NoSuchMember,
});
Error::new(kind, error.to_string())
}
fn position(part: &str) -> Option<usize> {
tree::position(part)
}
impl Protocol {
pub fn ie_name_of(&self, id: u16) -> Option<&'static str> {
let at = self.ie_names.binary_search_by_key(&id, |(known, _)| *known);
at.ok().map(|at| self.ie_names[at].1)
}
fn ie_name(&self, id: u16) -> String {
match self.ie_name_of(id) {
Some(name) => name.to_string(),
None => format!("@id={id}"),
}
}
fn entry_id(&self, entry: &Value) -> Option<u64> {
match entry.get("id")? {
Value::String(name) => (self.ie_id)(name).map(u64::from),
id => id.as_u64(),
}
}
fn selects_ies(&self, part: &str) -> bool {
matches!(part, "*" | "-")
|| part.starts_with("@id=")
|| position(part).is_some()
|| (self.ie_id)(part).is_some()
}
pub(crate) fn sent(&self, of: impl Fn(&'static str, u8, &'static str) -> bool) -> Option<Sent> {
let mut messages = self.messages.iter();
let message = messages.find(|(direction, code, name, ..)| of(direction, *code, name));
message.map(|(_, _, name, _, ies, ty)| Sent {
name,
ty: type_name(ty),
ies,
})
}
fn pdu(&self, view: &Value) -> Shape {
let code = view.get("procedure_code").and_then(Value::as_u64);
let direction = view.get("direction").and_then(Value::as_str);
Shape::Pdu(
self.sent(|of, procedure, _| {
Some(of) == direction && Some(u64::from(procedure)) == code
}),
)
}
pub fn enumeration(&self, name: &str) -> Option<&'static [&'static str]> {
let at = self
.enumerations
.binary_search_by(|(known, _)| (*known).cmp(name));
at.ok().map(|at| self.enumerations[at].1)
}
pub fn resolved(&self, mut shape: Shape) -> Shape {
for _ in 0..16 {
shape = match shape {
Shape::Named(name) => match (self.kind_of)(name) {
Some(Kind::Is(is)) => *is,
Some(_) => return shape,
None => return Shape::Plain,
},
shape => return shape,
};
}
Shape::Unknown
}
pub fn ie_value(&self, id: Option<u16>, extended: &str) -> Shape {
let Some(id) = id else {
return Shape::Unknown;
};
if self.carried.iter().any(|(carrier, ..)| *carrier == id) {
return Shape::Carrier(id);
}
let mut extensions = self.extension_types.iter();
if let Some((.., ty)) = extensions.find(|(known, of, _)| *known == id && *of == extended) {
return Shape::Named(type_name(ty));
}
match self.ie_types.iter().find(|(known, ..)| *known == id) {
Some((_, _, contained)) if !contained.is_empty() => {
Shape::Transfer(type_name(contained))
}
Some((_, ty, _)) => Shape::Named(type_name(ty)),
None => Shape::Unknown,
}
}
pub fn members(&self, shape: Shape, entry: Option<&Map>) -> Option<Vec<Member>> {
let has = |member: &str| entry.is_some_and(|entry| entry.contains_key(member));
let ie = |id: Option<u16>, extended: &str, value: &'static str, raw: &'static str| {
let of = |member: &str| {
let id = entry
.and_then(|entry| entry.get(member))
.and_then(Value::as_u64);
id.and_then(|id| u16::try_from(id).ok())
};
let decoded = match has("_decode_error") {
true => Shape::Undecoded,
false => self.ie_value(of("_original_id").or(of("id")).or(id), extended),
};
vec![
("id", Shape::Plain, false),
("criticality", Shape::Plain, false),
(value, decoded, true),
(raw, Shape::Plain, true),
("_original_id", Shape::Plain, true),
("_ie_name", Shape::Plain, true),
("_decode_error", Shape::Plain, true),
(EDITED, Shape::Plain, true),
(LOSSY, Shape::Plain, true),
]
};
Some(match shape {
Shape::Unknown | Shape::Undecoded => return None,
Shape::Pdu(message) => vec![
("procedure_code", Shape::Plain, false),
("direction", Shape::Plain, false),
("criticality", Shape::Plain, false),
(
MESSAGE,
message.map_or(Shape::AnyMessage, Shape::Message),
false,
),
("_raw_message", Shape::Plain, true),
(LOSSY, Shape::Plain, true),
],
Shape::Message(message) => {
let mut members = self.members(Shape::Named(message.ty), entry)?;
for (name, shape, _) in &mut members {
if *name == IES {
*shape = Shape::Ies(Some(message));
}
}
members
}
Shape::AnyMessage => vec![(IES, Shape::Ies(None), false)],
Shape::Named(name) => match (self.kind_of)(name) {
Some(Kind::Sequence(members) | Kind::Choice(members)) => {
let held = |(member, shape, optional): &Member| match shape {
Shape::Extensions(_) => (*member, Shape::Extensions(name), *optional),
Shape::Ies(None) if *member == IES => {
(*member, Shape::Ies(self.transfer(name)), *optional)
}
shape => (*member, *shape, *optional),
};
members.iter().map(held).collect()
}
Some(Kind::Is(is)) => return self.members(self.resolved(*is), entry),
None => Vec::new(),
},
Shape::Bits => vec![
("value", Shape::Plain, false),
("length", Shape::Plain, false),
],
Shape::Ie(id) => ie(id, "", "value", "_raw_value"),
Shape::Extension(id, extended) => ie(id, extended, "extensionValue", "_raw_value"),
Shape::Transfer(contained) => {
let decoded = match contained.is_empty() {
true => Shape::Unknown,
false => Shape::Named(contained),
};
vec![
("decoded", decoded, true),
("_raw_transfer", Shape::Plain, true),
("_decode_error", Shape::Plain, true),
(EDITED, Shape::Plain, true),
(LOSSY, Shape::Plain, true),
]
}
Shape::Carrier(id) => {
let carried = self.carried.iter().filter(|(carrier, ..)| *carrier == id);
carried
.map(|(_, name, ty)| (*name, Shape::Transfer(type_name(ty)), true))
.collect()
}
Shape::Plain | Shape::Null | Shape::List(_) | Shape::Ies(_) | Shape::Extensions(_) => {
Vec::new()
}
})
}
fn ie_of(&self, entry: &Value, shape: Shape) -> Option<u16> {
match shape {
Shape::Ie(_) | Shape::Extension(..) => {
self.entry_id(entry).and_then(|id| id.try_into().ok())
}
_ => None,
}
}
pub fn stays_on(&self, id: u16, extended: &str, part: &str) -> bool {
if (self.ie_id)(part) != Some(id) {
return false;
}
let value = match self.resolved(self.ie_value(Some(id), extended)) {
Shape::Transfer(contained) if !contained.is_empty() => Shape::Named(contained),
value => value,
};
let of_the_value = self.members(value, None).unwrap_or_default();
member(&of_the_value, part).is_none() || self.ie_name(id) == part
}
fn names_another_type(&self, part: &str, id: u16, extended: &str) -> bool {
let settled = |mut shape: Shape| {
for _ in 0..16 {
match shape {
Shape::Named(name) => match (self.kind_of)(name) {
Some(Kind::Is(is)) => shape = *is,
_ => break,
},
_ => break,
}
}
shape
};
let of_the_ie = settled(self.ie_value(Some(id), extended));
self.types.iter().any(|(_, kind)| match kind {
Kind::Sequence(members) | Kind::Choice(members) => (members.iter())
.any(|(name, shape, _)| same_name(name, part) && settled(*shape) != of_the_ie),
Kind::Is(_) => false,
})
}
pub fn named_ie(&self, shape: Shape, part: &str, named: bool) -> Option<Shape> {
let id = (self.ie_id)(part).filter(|_| named)?;
let (known, extension) = match shape {
Shape::Ie(known) => (known, None),
Shape::Extension(known, extended) => (known, Some(extended)),
_ => return None,
};
let extended = extended(shape);
let stays = match known {
Some(known) => known == id && self.stays_on(id, extended, part),
None => !self.names_another_type(part, id, extended),
};
stays.then_some(match extension {
Some(extended) => Shape::Extension(Some(id), extended),
None => Shape::Ie(Some(id)),
})
}
fn another_ie(
&self,
this: Option<u16>,
part: &str,
named: bool,
reason: &tree::Error,
) -> Option<tree::Error> {
let other = (self.ie_id)(part).filter(|_| named)?;
let this = this.filter(|this| *this != other)?;
let (this, other) = (self.ie_name(this), self.ie_name(other));
Some(reworded(reason.clone(), |reason| {
format!("this IE is {this}, not {other}: {reason}")
}))
}
fn no_member(&self, shape: Shape, members: &[Member], part: &str) -> tree::Error {
if let (Shape::Message(message), IES) = (shape, part) {
let has: Vec<_> = members.iter().map(|(name, ..)| *name).collect();
return fault(
ErrorKind::NoSuchMember,
format!(
"a message {} has no IEs under /{}: it has {}",
message.name,
self.root,
has.join(", ")
),
);
}
let of = match shape {
Shape::Named(name) => name.to_string(),
Shape::Message(message) => message.name.to_string(),
Shape::AnyMessage => {
"the message of a procedure that the tables do not have".to_string()
}
Shape::Pdu(_) => "a view".to_string(),
Shape::Bits => "a bit string".to_string(),
Shape::Transfer(_) => "a transfer".to_string(),
Shape::Ie(_) | Shape::Extension(..) => "an IE".to_string(),
_ => "this value".to_string(),
};
let names = names(shape, members);
fault(
ErrorKind::NoSuchMember,
match names.is_empty() {
true => format!("{part:?} is not a member of {of}, which has none"),
false => format!(
"{part:?} is not a member of {of}, which has {}",
names.join(", ")
),
},
)
}
fn transfer(&self, name: &str) -> Option<Sent> {
let mut transfers = self.transfers.iter();
let (asn, ty, ies, _) = transfers.find(|(_, ty, ..)| *ty == name)?;
Some(Sent { name: asn, ty, ies })
}
fn assigned(&self, container: Shape, id: u16) -> Option<&'static str> {
match container {
Shape::Ies(Some(message)) => {
let mut messages = self.message_ie_criticalities.iter();
let ies = match messages.find(|(name, _)| same_name(name, message.name)) {
Some((_, ies)) => *ies,
None => {
let mut transfers = self.transfers.iter();
let (.., ies) = transfers.find(|(name, ..)| *name == message.name)?;
*ies
}
};
let ie = ies.iter().find(|(known, _)| *known == id);
ie.map(|(_, criticality)| *criticality)
}
Shape::Ie(_) | Shape::List(Shape::Ie(_)) => {
let mut items = self.item_criticalities.iter();
items
.find(|(known, _)| *known == id)
.map(|(_, criticality)| *criticality)
}
_ => None,
}
}
fn message_of(&self, name: &str) -> Result<Sent, Error> {
let known = self.sent(|_, _, known| same_name(known, name));
known.ok_or_else(|| {
Error::new(
ErrorKind::UnknownMessage,
format!(
"{name:?} is not a message of {}{}",
self.name,
self.nearest_message(name)
),
)
})
}
fn ie_named(&self, name: &str) -> Result<u16, Error> {
(self.ie_id)(name).ok_or_else(|| {
Error::new(
ErrorKind::UnknownIe,
format!(
"{name:?} is not an IE of {}{}",
self.name,
self.nearest_ie(name)
),
)
})
}
pub(crate) fn nearest_ie(&self, name: &str) -> String {
let names: Vec<&str> = self.ie_names.iter().map(|(_, name)| *name).collect();
nearest_names(&names, name)
}
pub(crate) fn nearest_message(&self, name: &str) -> String {
let names: Vec<&str> = self.messages.iter().map(|(_, _, name, ..)| *name).collect();
nearest_names(&names, name)
}
}
fn nearest_names(names: &[&str], name: &str) -> String {
match oxirush_utils::tree::nearest(names, name, 3)[..] {
[] => String::new(),
[one] => format!(": the nearest name is {one}"),
[ref near @ .., last] => format!(": the nearest names are {} and {last}", near.join(", ")),
}
}
pub fn extended(shape: Shape) -> &'static str {
match shape {
Shape::Extensions(extended) | Shape::Extension(_, extended) => extended,
_ => "",
}
}
fn member<'m>(members: &'m [Member], part: &str) -> Option<&'m Member> {
let exact = members.iter().find(|(name, ..)| *name == part);
exact.or_else(|| {
let mut named = members.iter().filter(|(name, ..)| !name.starts_with('_'));
named.find(|(name, ..)| same_name(name, part))
})
}
fn key<'e>(entry: &'e Map, part: &str) -> Option<&'e str> {
let exact = entry.get_key_value(part).map(|(name, _)| name);
let named = || {
let mut names = entry.keys().filter(|name| !name.starts_with('_'));
names.find(|name| same_name(name, part))
};
exact.or_else(named).map(String::as_str)
}
fn has_octets(shape: Shape) -> bool {
matches!(
shape,
Shape::Ie(_) | Shape::Extension(..) | Shape::Transfer(_)
)
}
fn value_member(shape: Shape) -> Option<&'static str> {
match shape {
Shape::Ie(_) => Some("value"),
Shape::Extension(..) => Some("extensionValue"),
Shape::Transfer(_) => Some("decoded"),
_ => None,
}
}
fn names(shape: Shape, members: &[Member]) -> Vec<&'static str> {
let mut names: Vec<_> = (members.iter().map(|(name, ..)| *name))
.filter(|name| shown(name) && *name != "_decode_error" && *name != LOSSY)
.collect();
if has_octets(shape) {
names.push("octets");
}
names
}
fn or_its_own(reason: tree::Error, shape: Shape, members: &[Member]) -> tree::Error {
let of = match shape {
Shape::Transfer(_) => "a transfer",
_ => "an IE",
};
let own = names(shape, members).join(", ");
reworded(reason, |reason| format!("{reason}; {of} itself has {own}"))
}
fn no_position(part: &str) -> tree::Error {
fault(
ErrorKind::NoSuchMember,
format!(
"{part:?} is not a position in a list: an entry goes by its number, and \"*\" is \
each of them"
),
)
}
fn no_ie_there(part: &str) -> tree::Error {
fault(
ErrorKind::NoSuchMember,
format!("{part:?} selects an IE, and the entries of this list go by position"),
)
}
fn not_an_id(part: &str) -> tree::Error {
refusal(
ErrorKind::Path,
format!(
"{part:?} is not the identifier of an IE: \"@id=\" is followed by a number up to \
65535"
),
)
}
fn segment_id(protocol: &Protocol, part: &str, named: bool) -> Result<Option<u16>, tree::Error> {
match part.strip_prefix("@id=") {
Some(id) => id.parse::<u16>().map(Some).map_err(|_| not_an_id(part)),
None => Ok((protocol.ie_id)(part).filter(|_| named)),
}
}
fn element(shape: Shape) -> Shape {
match shape {
Shape::Ies(_) | Shape::List(Shape::Ie(_)) => Shape::Ie(None),
Shape::Extensions(extended) => Shape::Extension(None, extended),
Shape::List(Shape::Extension(_, extended)) => Shape::Extension(None, extended),
Shape::List(of) => *of,
_ => Shape::Unknown,
}
}
fn element_of(shape: Shape, id: u16) -> Option<Shape> {
match element(shape) {
Shape::Ie(_) => Some(Shape::Ie(Some(id))),
Shape::Extension(_, extended) => Some(Shape::Extension(Some(id), extended)),
Shape::Unknown => Some(Shape::Unknown),
_ => None,
}
}
fn shown(name: &str) -> bool {
!name.starts_with('_') || name == "_decode_error" || name == LOSSY
}
fn received(entry: &Map) -> Option<(&'static str, &Value)> {
let member = received_member(entry)?;
Some((member, &entry[member]))
}
fn received_member(entry: &Map) -> Option<&'static str> {
["_raw_value", "_raw_transfer"]
.into_iter()
.find(|member| entry.contains_key(member))
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct At {
shape: Shape,
named: bool,
taken: u8,
alternative: bool,
octets: bool,
}
impl At {
fn of(self, shape: Shape) -> Self {
Self {
shape,
named: self.named,
taken: self.taken.saturating_add(1),
..Self::default()
}
}
fn inside(self, shape: Shape) -> Self {
Self {
shape,
named: self.named,
taken: self.taken,
..Self::default()
}
}
}
type Opener<'e> = &'e dyn Fn(Value, &str) -> Value;
struct Views<'e> {
protocol: &'static Protocol,
message: Option<Sent>,
written_text: bool,
opens: Option<Opener<'e>>,
}
impl<'e> Views<'e> {
fn new(protocol: &'static Protocol) -> Self {
Self {
protocol,
message: None,
written_text: false,
opens: None,
}
}
}
impl Family for Views<'_> {
type Shape = At;
fn root(&self) -> Root<'_> {
Root::new(self.protocol.root, &[MESSAGE, IES], false)
}
fn start(&self, tree: &Value, rooted: bool) -> At {
let shape = match self.message {
Some(message) => Shape::Pdu(Some(message)),
None => self.protocol.pdu(tree),
};
At {
shape,
named: rooted,
..At::default()
}
}
fn step<'v>(
&self,
place: &Place<'v, At>,
part: &str,
next: &mut Next<'v, At>,
) -> Result<Step<At>, tree::Error> {
let taken = self.take(place, part, next);
match (taken, next.edit()) {
(Err(reason), Some(edit))
if edit != Edit::Open && reason.kind() != tree::ErrorKind::Refused =>
{
let again = refusal(ErrorKind::NoSuchMember, reason.reason());
Err(match reason.code() {
Some(code) => again.with_code(code),
None => again,
})
}
(taken, _) => taken.map(|()| Step::Taken),
}
}
fn null_is_value(&self, at: &At) -> bool {
self.protocol.resolved(at.shape) == Shape::Null
}
fn edited(&self, tree: &mut Value, keys: &[Key], at: &At, edit: Edit) {
let Some((last, before)) = keys.split_last() else {
return;
};
let mark = |entry: &mut Map, name: &str| {
if VALUES.contains(&name) && received_member(entry).is_some() {
entry.insert(EDITED.into(), true.into());
}
};
let mut holder = &mut *tree;
for key in before {
if let (Key::Name(name), Value::Object(entry)) = (key, &mut *holder) {
mark(entry, name);
}
holder = match (key, holder) {
(Key::Name(name), Value::Object(entry)) => match entry.get_mut(name.as_str()) {
Some(value) => value,
None => return,
},
(Key::Position(position), Value::Array(entries)) => {
match entries.get_mut(*position) {
Some(value) => value,
None => return,
}
}
_ => return,
};
}
let (Key::Name(name), Value::Object(entry)) = (last, holder) else {
return;
};
if edit != Edit::Set {
return;
}
mark(entry, name);
if at.octets {
for value in VALUES.into_iter().chain(["_decode_error", EDITED]) {
entry.shift_remove(value);
}
}
if at.alternative {
entry.retain(|member, _| member == name);
}
}
}
impl Views<'_> {
fn take<'v>(
&self,
place: &Place<'v, At>,
part: &str,
next: &mut Next<'v, At>,
) -> Result<(), tree::Error> {
let at = *place.shape();
if let Some(id) = part.strip_prefix("@id=")
&& id.parse::<u16>().is_err()
{
return Err(not_an_id(part));
}
if at.named && at.taken == 2 && !self.protocol.selects_ies(part) {
let nearest = self.protocol.nearest_ie(part);
return Err(refusal(
ErrorKind::UnknownIe,
format!("{part:?} is not an IE of {}{nearest}", self.protocol.name),
));
}
let shape = self.protocol.resolved(at.shape);
match place.value() {
Some(whole @ Value::Object(entry)) => {
self.object(place, whole, entry, at, shape, part, next)?
}
Some(Value::Array(entries)) => self.list(entries, at, shape, part, next)?,
Some(Value::Null) | None => {
if next.edit().is_none() {
self.typed(at, shape, part, next)?;
}
}
Some(value) => self.scalar(place, value, at, shape, part, next)?,
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn object<'v>(
&self,
place: &Place<'v, At>,
whole: &'v Value,
entry: &'v Map,
at: At,
shape: Shape,
part: &str,
next: &mut Next<'v, At>,
) -> Result<(), tree::Error> {
let protocol = self.protocol;
let (edit, last, named) = (next.edit(), next.is_last(), at.named);
let members = protocol.members(shape, Some(entry));
if named
&& protocol.selects_ies(part)
&& !entry.contains_key(part)
&& let Some(Value::Array(_)) = entry.get(IES)
{
let of = members.as_deref().and_then(|members| member(members, IES));
let ies = at.inside(of.map_or(Shape::Ies(None), |(_, shape, _)| *shape));
return next.through(place, IES, ies, |inside, next| {
self.take(inside, part, next)
});
}
if part == "*" {
if edit.is_some_and(|edit| edit != Edit::Open) {
return Err(refusal(
ErrorKind::NoSuchMember,
format!("{part:?} selects among the entries of a list, and this is no list"),
));
}
for (name, value) in entry.iter().filter(|(name, _)| shown(name)) {
let known = members.as_deref().and_then(|members| member(members, name));
let of = known.map_or(Shape::Unknown, |(_, shape, _)| *shape);
next.member(name, value, at.of(of));
}
return Ok(());
}
let held = value_member(shape);
if part.starts_with("@id=") && held.is_none() {
return Err(fault(
ErrorKind::NoSuchMember,
format!("{part:?} selects among the IEs of a list, and this is no list"),
));
}
if same_name(part, "octets") {
if let Some(edit) = edit {
let raw = received_member(entry).or(match shape {
Shape::Ie(_) | Shape::Extension(..) => Some("_raw_value"),
Shape::Transfer(_) => Some("_raw_transfer"),
_ => None,
});
if let Some(raw) = raw.filter(|_| last) {
let octets = At {
octets: true,
..at.of(Shape::Plain)
};
match (edit, self.written_text) {
(Edit::Set, true) => match entry.get(raw) {
Some(value) => next.member(raw, value, octets),
None => next.absent(raw, octets),
},
(Edit::Open, _) => {}
_ => {
return Err(refusal(ErrorKind::Edit, "octets are set, in hexadecimal"));
}
}
return Ok(());
}
} else if has_octets(shape) || received(entry).is_some() {
if entry.contains_key(EDITED) {
return Err(refusal(
ErrorKind::Edit,
"the value was edited since these octets were received",
));
}
match received(entry) {
Some((name, octets)) => next.member(name, octets, at.of(Shape::Plain)),
None => next.absent_once(part, at.of(Shape::Plain)),
}
return Ok(());
}
}
let Some(members) = members else {
let name = key(entry, part);
if let Some(edit) = edit
&& last
{
refuse(edit, name.unwrap_or(part), entry, false, true)?;
}
return match name {
Some(name) => {
next.member(name, &entry[name], at.of(Shape::Unknown));
Ok(())
}
None if edit.is_some() && last => {
next.absent(part, at.of(Shape::Unknown));
Ok(())
}
None => Err(fault(
ErrorKind::NoSuchMember,
format!("{part:?} is not a member of this value"),
)),
};
};
let own = member(&members, part);
let this = protocol
.ie_of(whole, shape)
.filter(|_| named && own.is_none());
if this.is_some_and(|this| protocol.stays_on(this, extended(shape), part)) {
next.stay(place, at);
return Ok(());
}
let held = held.and_then(|held| member(&members, held));
let Some((name, of, optional)) = own.or(held).copied() else {
return Err(protocol.no_member(shape, &members, part));
};
let value = match entry.get(name) {
None if name == "decoded" && entry.contains_key("_decode_error") && edit.is_some() => {
return Ok(());
}
None if name == "decoded" && entry.contains_key("_decode_error") => {
let error = entry["_decode_error"].as_str().unwrap_or_default();
return Err(refusal(
ErrorKind::UndecodableIe,
format!("the transfer did not decode: {error}"),
));
}
value => value,
};
if own.is_some() {
let alternative = matches!(shape, Shape::Named(name) if matches!((protocol.kind_of)(name), Some(Kind::Choice(_))));
if let Some(edit) = edit
&& last
{
refuse(edit, name, entry, alternative, optional)?;
}
let child = At {
alternative,
..at.of(of)
};
match value {
Some(value) => next.member(name, value, child),
None if edit.is_some() => {
if last && edit == Some(Edit::Set) {
next.absent(name, child);
}
}
None => next.absent_once(name, child),
}
return Ok(());
}
let taken = next.through(place, name, at.inside(of), |inside, next| {
self.take(inside, part, next)
});
taken.map_err(|reason| match reason.kind() {
tree::ErrorKind::Refused => reason,
_ => match protocol.another_ie(this, part, named, &reason) {
Some(another) => another,
None => or_its_own(reason, shape, &members),
},
})
}
fn list<'v>(
&self,
entries: &'v [Value],
at: At,
shape: Shape,
part: &str,
next: &mut Next<'v, At>,
) -> Result<(), tree::Error> {
let protocol = self.protocol;
let of = at.of(element(shape));
if part == "*" {
for (index, entry) in entries.iter().enumerate() {
next.entry(index, entry, of);
}
return Ok(());
}
if part == "-" && next.edit() == Some(Edit::Insert) && next.is_last() {
next.end(of);
return Ok(());
}
if let Some(id) = segment_id(protocol, part, at.named)? {
let Some(absent) = element_of(shape, id) else {
return Err(no_ie_there(part));
};
let mut found = false;
for (index, entry) in entries.iter().enumerate() {
if protocol.entry_id(entry) == Some(u64::from(id)) {
next.entry(index, entry, of);
found = true;
}
}
if !found && next.edit().is_none() {
next.absent_once(part, at.of(absent));
}
return Ok(());
}
let Some(index) = position(part) else {
return Err(no_position(part));
};
if let Some(entry) = entries.get(index) {
next.entry(index, entry, of);
}
Ok(())
}
fn typed(
&self,
at: At,
shape: Shape,
part: &str,
next: &mut Next<'_, At>,
) -> Result<(), tree::Error> {
let protocol = self.protocol;
let named = at.named;
match shape {
Shape::Unknown | Shape::Undecoded => next.absent_once(part, at.of(Shape::Unknown)),
Shape::List(_) | Shape::Ies(_) | Shape::Extensions(_) => {
if let Some(id) = segment_id(protocol, part, named)? {
let Some(of) = element_of(shape, id) else {
return Err(no_ie_there(part));
};
if let Shape::Ies(Some(message)) = shape
&& !part.starts_with("@id=")
&& !message.ies.iter().any(|(known, _)| *known == id)
{
let ies: Vec<_> = (message.ies.iter())
.map(|(id, _)| protocol.ie_name(*id))
.collect();
return Err(fault(
ErrorKind::NoSuchMember,
format!(
"{part:?} is not an IE of {}, which has {}",
message.name,
ies.join(", ")
),
));
}
next.absent_once(part, at.of(of));
} else if matches!(part, "*" | "-") || position(part).is_some() {
match shape {
Shape::Ies(Some(message)) => {
for (id, _) in message.ies {
next.absent_once(part, at.of(Shape::Ie(Some(*id))));
}
}
shape => next.absent_once(part, at.of(element(shape))),
}
} else {
return Err(no_position(part));
}
}
shape => {
let members = protocol.members(shape, None).unwrap_or_default();
if named
&& protocol.selects_ies(part)
&& member(&members, part).is_none()
&& let Some((_, ies, _)) = member(&members, IES)
{
return self.typed(at, *ies, part, next);
}
if part == "*" {
for (name, of, _) in members.iter().filter(|(name, ..)| shown(name)) {
next.absent_once(name, at.of(*of));
}
} else if same_name(part, "octets") && has_octets(shape) {
next.absent_once(part, at.of(Shape::Plain));
} else if let Some((name, of, _)) = member(&members, part) {
next.absent_once(name, at.of(*of));
} else if let Some(ie) = protocol.named_ie(shape, part, named) {
next.absent_once(part, at.of(ie));
} else if let Some((_, of, _)) =
value_member(shape).and_then(|held| member(&members, held))
{
let this = match shape {
Shape::Ie(known) | Shape::Extension(known, _) => known,
_ => None,
};
let taken = self.typed(at, protocol.resolved(*of), part, next);
return taken.map_err(|reason| match reason.kind() {
tree::ErrorKind::Refused => reason,
_ => match protocol.another_ie(this, part, named, &reason) {
Some(another) => another,
None => or_its_own(reason, shape, &members),
},
});
} else {
return Err(protocol.no_member(shape, &members, part));
}
}
}
Ok(())
}
fn scalar<'v>(
&self,
place: &Place<'v, At>,
value: &'v Value,
at: At,
shape: Shape,
part: &str,
next: &mut Next<'v, At>,
) -> Result<(), tree::Error> {
let protocol = self.protocol;
match shape {
Shape::Undecoded if next.edit().is_some() => {}
Shape::Undecoded => {
return Err(refusal(ErrorKind::UndecodableIe, "the IE did not decode"));
}
_ if part == "*" => {}
Shape::Bits if ["value", "length"].contains(&part) => {}
Shape::Transfer(_) if same_name(part, "octets") => {
next.stay(place, at.of(Shape::Plain));
}
Shape::Transfer(_) if same_name(part, "decoded") => {}
Shape::Transfer(contained) if !contained.is_empty() => {
if next.edit().is_none() {
let taken = self.typed(at, Shape::Named(contained), part, next);
let own = protocol.members(shape, None).unwrap_or_default();
taken.map_err(|reason| match reason.kind() {
tree::ErrorKind::Refused => reason,
_ => or_its_own(reason, shape, &own),
})?;
}
}
Shape::Carrier(_) => {
let carried = protocol.members(shape, None).unwrap_or_default();
return match member(&carried, part) {
Some((name, ..)) => match (next.edit(), self.opens, value) {
(Some(Edit::Open), Some(decode), Value::String(_)) => {
let mut opened = Map::new();
opened.insert(name.to_string(), decode(value.clone(), name));
next.open(place, Value::Object(opened));
Ok(())
}
_ => Err(refusal(
ErrorKind::NotOpened,
format!("the octets are not shown as a {name}: open decodes them"),
)),
},
None => Err(protocol.no_member(shape, &carried, part)),
};
}
Shape::Plain => return Err(protocol.no_member(shape, &[], part)),
_ => {
return Err(fault(
ErrorKind::NoSuchMember,
format!("{part:?} is not a member of this value, which has none"),
));
}
}
Ok(())
}
}
fn refuse(
edit: Edit,
name: &str,
entry: &Map,
alternative: bool,
optional: bool,
) -> Result<(), tree::Error> {
let refused = |reason: String| Err(refusal(ErrorKind::Edit, reason));
match edit {
Edit::Remove => {
let value = match name {
"value" | "extensionValue" => entry.contains_key("id"),
"decoded" => entry.contains_key("_raw_transfer"),
_ => false,
};
if value {
return refused(format!(
"{name} is not taken out: remove what has it, or set its octets"
));
}
if alternative {
return refused(format!(
"{name} is not taken out: a CHOICE has one alternative, set another in \
its place"
));
}
if !optional {
return refused(format!("{name} is not taken out: its type always has it"));
}
Ok(())
}
Edit::Insert => refused("insert adds to a list".to_string()),
_ => Ok(()),
}
}
pub fn select<'v>(
protocol: &'static Protocol,
view: &'v Value,
path: &str,
) -> Result<Vec<&'v Value>, Error> {
tree::select_in(&Views::new(protocol), view, path).map_err(error)
}
pub fn check_path(protocol: &'static Protocol, message: &str, path: &str) -> Result<(), Error> {
let message = protocol.message_of(message)?;
let views = Views {
message: Some(message),
..Views::new(protocol)
};
let places = tree::places_in(&views, &Value::Null, path).map_err(error)?;
if !places.is_empty() {
return Ok(());
}
let parts = tree::segments(path).map_err(error)?;
for end in 1..=parts.len() {
let prefix: String = parts[..end]
.iter()
.map(|part| format!("/{}", tree::escape(part)))
.collect();
let selected = tree::places_in(&views, &Value::Null, &prefix).map_err(error)?;
if selected.is_empty() {
return Err(Error::new(
ErrorKind::NoSuchMember,
format!(
"{path} selects nothing in a message {}: a value before {:?} has no members",
message.name,
parts[end - 1]
),
));
}
}
Ok(())
}
pub fn enumerated_at(
protocol: &'static Protocol,
message: &str,
path: &str,
) -> Result<Option<&'static [&'static str]>, Error> {
let message = protocol.message_of(message)?;
let views = Views {
message: Some(message),
..Views::new(protocol)
};
let places = tree::places_in(&views, &Value::Null, path).map_err(error)?;
let mut names = None;
for place in places {
let mut shape = place.shape().shape;
for _ in 0..16 {
match shape {
Shape::Named(name) => match (protocol.kind_of)(name) {
Some(Kind::Is(is)) => shape = *is,
_ => break,
},
_ => break,
}
}
let Shape::Named(name) = shape else {
return Ok(None);
};
match (protocol.enumeration(name), names) {
(Some(of), None) => names = Some(of),
(Some(of), Some(other)) if of == other => {}
_ => return Ok(None),
}
}
Ok(names)
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
enum Listing {
#[default]
Other,
View,
Message,
Ies,
Octets,
}
struct Paths(&'static Protocol);
impl Paths {
fn of(value: Option<&Value>) -> Listing {
match value.and_then(Value::as_object) {
Some(entry)
if received(entry).is_some()
&& !VALUES.iter().any(|value| entry.contains_key(value)) =>
{
Listing::Octets
}
_ => Listing::Other,
}
}
}
impl Family for Paths {
type Shape = Listing;
fn root(&self) -> Root<'_> {
Root::new(self.0.root, &[MESSAGE, IES], false)
}
fn start(&self, _tree: &Value, _rooted: bool) -> Listing {
Listing::View
}
fn member(&self, shape: &Listing, name: &str, value: Option<&Value>) -> Listing {
match (shape, name) {
(Listing::View, MESSAGE) => Listing::Message,
(_, IES) if value.is_some_and(Value::is_array) => Listing::Ies,
_ => Self::of(value),
}
}
fn entry(&self, _shape: &Listing, value: Option<&Value>) -> Listing {
Self::of(value)
}
fn null_is_value(&self, _shape: &Listing) -> bool {
true
}
fn listed(&self, shape: &Listing, name: &str) -> Listed {
match (shape, name) {
(Listing::Octets, "_raw_value" | "_raw_transfer") => Listed::As("octets"),
(_, name) if !shown(name) => Listed::Hidden,
(Listing::Message, IES) => Listed::Root,
(_, IES) => Listed::Through,
_ => Listed::Member,
}
}
fn entry_names(&self, shape: &Listing, list: &[Value]) -> Option<Vec<Option<String>>> {
if *shape != Listing::Ies {
return None;
}
let ids: Vec<Option<u64>> = list.iter().map(|ie| self.0.entry_id(ie)).collect();
let mut times: BTreeMap<u64, usize> = BTreeMap::new();
for id in ids.iter().flatten() {
*times.entry(*id).or_default() += 1;
}
let name = |id: &Option<u64>| {
let id = (*id)?;
let known = u16::try_from(id).ok().filter(|_| times[&id] == 1)?;
self.0.ie_name_of(known).map(str::to_string)
};
Some(ids.iter().map(name).collect())
}
}
pub fn paths(protocol: &'static Protocol, view: &Value) -> Vec<(String, Value)> {
tree::paths_in(&Paths(protocol), view)
}
pub fn written_ie(protocol: &'static Protocol, entry: &mut Map) -> Result<(), Error> {
let id = match entry.get("id") {
Some(Value::String(name)) => Some(oxirush_utils::tree!(protocol.ie_named(name)?)),
Some(Value::Number(_)) => None,
_ => return Ok(()),
};
if let Some(id) = id {
entry.insert("id".into(), id);
}
if let Some(octets) = entry.shift_remove("octets") {
if VALUES.iter().any(|value| entry.contains_key(value)) {
return Err(Error::new(
ErrorKind::Form,
"an IE is written with its value or its octets, not both",
));
}
entry.insert("_raw_value".into(), octets);
}
Ok(())
}
fn as_viewed(protocol: &'static Protocol, mut value: Value) -> Result<Value, Error> {
if let Some(entry) = value.as_object_mut() {
written_ie(protocol, entry)?;
}
Ok(value)
}
pub fn set(
protocol: &'static Protocol,
view: &mut Value,
path: &str,
value: Value,
) -> Result<(), Error> {
let value = as_viewed(protocol, value)?;
let views = Views {
written_text: value.is_string(),
..Views::new(protocol)
};
tree::set_in(&views, view, path, value).map_err(error)
}
pub fn remove(protocol: &'static Protocol, view: &mut Value, path: &str) -> Result<(), Error> {
tree::remove_in(&Views::new(protocol), view, path).map_err(error)
}
pub fn insert(
protocol: &'static Protocol,
view: &mut Value,
path: &str,
value: Value,
) -> Result<(), Error> {
let value = as_viewed(protocol, value)?;
tree::insert_in(&Views::new(protocol), view, path, value).map_err(error)
}
pub fn open(protocol: &'static Protocol, view: &mut Value, path: &str) -> Result<(), Error> {
let opened = |raw: Value, name: &str| protocol.opened(raw, name);
let views = Views {
opens: Some(&opened),
..Views::new(protocol)
};
tree::open_in(&views, view, path).map_err(error)
}
pub fn of_a_transfer(name: &str) -> bool {
name.starts_with('_') || ["decoded", "octets"].contains(&name)
}
pub enum Members {
Listed(&'static [Member], &'static str),
Made(Vec<Member>),
}
impl Protocol {
pub fn member_shapes(&self, shape: Shape, entry: &Map) -> Members {
let shape = match self.resolved(shape) {
Shape::Transfer(contained)
if !contained.is_empty() && !entry.keys().any(|name| of_a_transfer(name)) =>
{
self.resolved(Shape::Named(contained))
}
shape => shape,
};
if let Shape::Named(name) = shape
&& let Some(Kind::Sequence(members) | Kind::Choice(members)) = (self.kind_of)(name)
&& !(matches!(members, [(IES, Shape::Ies(None), _)]) && self.transfer(name).is_some())
{
return Members::Listed(members, name);
}
Members::Made(self.members(shape, Some(entry)).unwrap_or_default())
}
pub fn entry_shape(&self, shape: Shape) -> Shape {
element(self.resolved(shape))
}
pub fn message_shape(&self, direction: &str, code: u8) -> Shape {
let message = self.sent(|of, procedure, _| procedure == code && of == direction);
message.map_or(Shape::AnyMessage, Shape::Message)
}
pub fn carried_shape(&self, name: &str) -> Shape {
let mut carried = self.carried.iter();
let carried = carried.find(|(_, known, _)| same_name(known, name));
carried.map_or(Shape::Unknown, |(.., ty)| Shape::Transfer(type_name(ty)))
}
pub(crate) fn by_name(&self, value: Value, shape: Shape) -> Result<Value, Error> {
let shape = self.resolved(shape);
match value {
Value::Object(mut entry) => match shape {
Shape::Transfer(_) => {
let members = self.members(shape, Some(&entry)).unwrap_or_default();
let of = member(&members, "decoded").map(|(_, of, _)| *of);
let decoded = entry.shift_remove("decoded");
let decoded = decoded.filter(|_| !entry.contains_key(LOSSY));
match (decoded, of) {
(Some(decoded), Some(of)) => self.by_name(decoded, of),
_ => {
let octets =
received_member(&entry).and_then(|raw| entry.shift_remove(raw));
Ok(octets_alone(octets.unwrap_or_default()))
}
}
}
Shape::Ie(_) | Shape::Extension(..) => self.ie_by_name(entry, shape, shape),
_ => {
let members = self.member_shapes(shape, &entry);
for (name, value) in entry.iter_mut() {
*value = self.by_name(value.take(), member_shape(&members, name))?;
}
Ok(Value::Object(entry))
}
},
Value::Array(mut entries) => {
let of = element(shape);
for entry in &mut entries {
*entry = match (of, entry.take()) {
(Shape::Ie(_) | Shape::Extension(..), Value::Object(entry)) => {
self.ie_by_name(entry, of, shape)?
}
(Shape::Ie(_) | Shape::Extension(..), _) => return Err(no_identifier()),
(of, entry) => self.by_name(entry, of)?,
};
}
Ok(Value::Array(entries))
}
plain => Ok(plain),
}
}
fn ie_by_name(&self, mut entry: Map, shape: Shape, container: Shape) -> Result<Value, Error> {
let id = match entry.get("id") {
Some(Value::String(name)) => (self.ie_id)(name),
Some(id) => id.as_u64().and_then(|id| u16::try_from(id).ok()),
None => None,
};
let id = id.ok_or_else(no_identifier)?;
let name = self
.ie_name_of(id)
.map_or_else(|| id.to_string(), str::to_string);
let field = value_member(shape).unwrap_or("value");
let value = entry.shift_remove(field).unwrap_or_default();
let undecoded = entry.contains_key("_decode_error")
|| entry.contains_key(LOSSY)
|| value.get("_decode_error").is_some()
|| value.get(LOSSY).is_some();
let value = match undecoded {
true => octets_alone(entry.shift_remove("_raw_value").unwrap_or_default()),
false => self.by_name(value, self.ie_value(Some(id), extended(shape)))?,
};
let criticality = entry.shift_remove("criticality").unwrap_or_default();
let mut shown = Map::new();
shown.insert(name, value);
if criticality.as_str() != self.assigned(container, id) {
shown.insert("criticality".into(), criticality);
}
Ok(Value::Object(shown))
}
pub(crate) fn written(
&self,
value: &Value,
shape: Shape,
depth: usize,
) -> Result<Value, Error> {
if depth > WRITTEN {
return Err(Error::new(
ErrorKind::Limit,
format!("a written tree nests deeper than {WRITTEN}"),
));
}
let shape = self.resolved(shape);
match value {
Value::Object(entry) => match shape {
Shape::Transfer(_) => {
let members = self.members(shape, None).unwrap_or_default();
let decoded = member(&members, "decoded");
let decoded = decoded.map_or(Shape::Unknown, |(_, of, _)| *of);
if !entry.keys().any(|name| of_a_transfer(name)) {
return self.written(value, decoded, depth + 1);
}
let mut entry = entry.clone();
if let Some(value) = entry.get_mut("decoded") {
*value = self.written(value, decoded, depth + 1)?;
}
Ok(Value::Object(entry))
}
Shape::Ie(_) | Shape::Extension(..) => self.entry_of(value, shape, shape, depth),
_ => {
let members = self.member_shapes(shape, entry);
let listed = entry.iter().map(|(name, value)| {
let of = member_shape(&members, name);
Ok((name.clone(), self.written(value, of, depth + 1)?))
});
Ok(Value::Object(listed.collect::<Result<_, Error>>()?))
}
},
Value::Array(entries) => {
let listed = entries.iter().map(|entry| match element(shape) {
of @ (Shape::Ie(_) | Shape::Extension(..)) => {
self.entry_of(entry, of, shape, depth)
}
of => self.written(entry, of, depth + 1),
});
Ok(Value::Array(listed.collect::<Result<_, Error>>()?))
}
plain => Ok(plain.clone()),
}
}
fn entry_of(
&self,
ie: &Value,
shape: Shape,
container: Shape,
depth: usize,
) -> Result<Value, Error> {
const IE: &str = "each entry of a container is one IE: its name with its value";
let field = value_member(shape).unwrap_or("value");
let entry = ie
.as_object()
.ok_or_else(|| Error::new(ErrorKind::Form, IE))?;
if entry.contains_key("id") {
let id = self.entry_id(ie).and_then(|id| u16::try_from(id).ok());
let mut entry = entry.clone();
if let Some(value) = entry.get_mut(field) {
*value = self.written(value, self.ie_value(id, extended(shape)), depth + 1)?;
}
return Ok(Value::Object(entry));
}
let mut members = entry.iter().filter(|(member, _)| *member != "criticality");
let (Some((name, value)), None) = (members.next(), members.next()) else {
return Err(Error::new(ErrorKind::Form, IE));
};
let id = match name.parse::<u16>() {
Ok(id) => id,
Err(_) => self.ie_named(name)?,
};
let criticality = match (
entry.get("criticality"),
self.assigned(container, id),
container,
) {
(Some(criticality), ..) => criticality.clone(),
(None, Some(criticality), _) => oxirush_utils::tree!(criticality),
(None, None, Shape::Ies(Some(message))) => {
return Err(Error::new(
ErrorKind::Form,
format!(
"{} has no IE {name}: one that is sent in it says its \"criticality\"",
message.name
),
));
}
(None, None, _) => {
return Err(Error::new(
ErrorKind::Form,
format!("{name} says its \"criticality\" here: the tables have none for it"),
));
}
};
let mut listed = Map::new();
listed.insert("id".into(), id.into());
listed.insert("criticality".into(), criticality);
let octets = value.as_object().filter(|value| value.len() == 1);
match octets.and_then(|value| value.get("octets")) {
Some(octets) => listed.insert("octets".into(), octets.clone()),
None => {
let value =
self.written(value, self.ie_value(Some(id), extended(shape)), depth + 1)?;
listed.insert(field.into(), value)
}
};
Ok(Value::Object(listed))
}
}
impl Protocol {
pub fn jer(&self, mut value: Value, ty: &'static str) -> Value {
self.to_jer(&mut value, Shape::Named(ty), 0);
value
}
pub fn from_jer(&self, value: &mut Value, shape: Shape) {
self.of_jer(value, shape, 0);
}
fn of_jer(&self, value: &mut Value, mut shape: Shape, depth: usize) {
if depth > WRITTEN {
return;
}
for _ in 0..16 {
let Shape::Named(name) = shape else {
break;
};
if let Some(form) = (self.type_form)(name) {
*value = crate::json::readable(form, value.clone());
return;
}
match (self.kind_of)(name) {
Some(Kind::Is(is)) => shape = *is,
_ => break,
}
}
match value {
Value::Object(object) => {
let members = self.member_shapes(shape, object);
for (key, child) in object.iter_mut() {
self.of_jer(child, member_shape(&members, key), depth + 1);
}
}
Value::Array(entries) => {
let entry = self.entry_shape(shape);
for child in entries {
self.of_jer(child, entry, depth + 1);
}
}
_ => {}
}
}
fn to_jer(&self, value: &mut Value, shape: Shape, depth: usize) {
if depth > WRITTEN {
return;
}
match shape {
Shape::Named(name) => {
if let Some(form) = (self.type_form)(name) {
if let Ok(jer) = form.write(value) {
*value = jer;
}
return;
}
match (self.kind_of)(name) {
Some(Kind::Sequence(members) | Kind::Choice(members)) => {
for (key, child) in value.as_object_mut().into_iter().flatten() {
if let Some((_, of, _)) = member(members, key) {
self.to_jer(child, *of, depth + 1);
}
}
}
Some(Kind::Is(is)) => self.to_jer(value, *is, depth + 1),
None => {}
}
}
Shape::List(of) => {
for entry in value.as_array_mut().into_iter().flatten() {
self.to_jer(entry, *of, depth + 1);
}
}
_ => {}
}
}
}
pub fn member_shape(members: &Members, name: &str) -> Shape {
let (members, of) = match members {
Members::Listed(members, of) => (*members, Some(*of)),
Members::Made(members) => (&members[..], None),
};
match (member(members, name), of) {
(Some((_, Shape::Extensions(_), _)), Some(of)) => Shape::Extensions(of),
(Some((_, shape, _)), _) => *shape,
(None, _) => Shape::Unknown,
}
}
fn octets_alone(octets: Value) -> Value {
let mut alone = Map::new();
alone.insert("octets".into(), octets);
Value::Object(alone)
}
fn no_identifier() -> Error {
Error::new(ErrorKind::Form, "an IE has its identifier")
}
pub fn named_ies(protocol: &'static Protocol, message: &str, ies: Value) -> Result<Value, Error> {
let message = protocol.sent(|_, _, name| same_name(name, message));
protocol.by_name(ies, Shape::Ies(message))
}
pub fn listed_ies(protocol: &'static Protocol, message: &str, ies: &Value) -> Result<Value, Error> {
let message = protocol.sent(|_, _, name| same_name(name, message));
protocol.written(ies, Shape::Ies(message), 0)
}