use super::{v211, v221, BuilderKind, Enum, Integrity, Number, Slot, Str};
#[expect(
clippy::large_enum_variant,
reason = "transient builder state; the large variants are moved into the compact IR and dropped"
)]
#[derive(Debug)]
pub(super) enum Node<'buf> {
Ignore,
Str(Str<'buf>),
Number(Number<'buf>),
Enum(Enum<'buf>),
Bool,
Array(Vec<Integrity<Node<'buf>>>),
Tariff(v221::Tariff<'buf>),
Cdr(v221::Cdr<'buf>),
ChargingPeriod(v221::ChargingPeriod<'buf>),
CdrDimension(v221::Dimension<'buf>),
Element(v221::Element<'buf>),
PriceComponent(v221::PriceComponent<'buf>),
Restrictions(v221::Restrictions<'buf>),
Price(v221::Price<'buf>),
V211Tariff(v211::Tariff<'buf>),
V211Element(v211::Element<'buf>),
V211PriceComponent(v211::PriceComponent<'buf>),
V211Restrictions(v211::Restrictions<'buf>),
V211Cdr(v211::Cdr<'buf>),
V211ChargingPeriod(v211::ChargingPeriod<'buf>),
V211CdrDimension(v211::Dimension<'buf>),
}
pub(super) fn empty<'buf>(kind: BuilderKind) -> Node<'buf> {
match kind {
BuilderKind::Ignore => Node::Ignore,
BuilderKind::V221Tariff => Node::Tariff(v221::Tariff::default()),
BuilderKind::V221Element => Node::Element(v221::Element::default()),
BuilderKind::V221PriceComponent => Node::PriceComponent(v221::PriceComponent::default()),
BuilderKind::V221Restrictions => Node::Restrictions(v221::Restrictions::default()),
BuilderKind::V221Price => Node::Price(v221::Price::default()),
BuilderKind::V221Cdr => Node::Cdr(v221::Cdr::default()),
BuilderKind::V221ChargingPeriod => Node::ChargingPeriod(v221::ChargingPeriod::default()),
BuilderKind::V221CdrDimension => Node::CdrDimension(v221::Dimension::default()),
BuilderKind::V211Tariff => Node::V211Tariff(v211::Tariff::default()),
BuilderKind::V211Element => Node::V211Element(v211::Element::default()),
BuilderKind::V211PriceComponent => {
Node::V211PriceComponent(v211::PriceComponent::default())
}
BuilderKind::V211Restrictions => Node::V211Restrictions(v211::Restrictions::default()),
BuilderKind::V211Cdr => Node::V211Cdr(v211::Cdr::default()),
BuilderKind::V211ChargingPeriod => {
Node::V211ChargingPeriod(v211::ChargingPeriod::default())
}
BuilderKind::V211CdrDimension => Node::V211CdrDimension(v211::Dimension::default()),
}
}
impl<'buf> Node<'buf> {
pub(super) fn route_to_parent(
&mut self,
builders: &mut [Node<'buf>],
slot: Slot,
value: Integrity<Node<'buf>>,
) {
match slot {
Slot::Root => {
if let Integrity::Ok(node) = value {
*self = node;
}
}
Slot::Ignore => {}
Slot::Field { name } => {
set_top_field(builders, name, value);
}
Slot::Item => {
if let Some(top) = builders.last_mut() {
top.push(value);
}
}
}
}
fn set(&mut self, field: &'static str, child: Integrity<Node<'buf>>) {
match self {
Node::Tariff(tariff) => set_tariff(tariff, field, child),
Node::Cdr(cdr) => set_cdr(cdr, field, child),
Node::ChargingPeriod(period) => set_charging_period(period, field, child),
Node::CdrDimension(dimension) => set_dimension(dimension, field, child),
Node::Element(element) => set_element(element, field, child),
Node::PriceComponent(component) => set_price_component(component, field, child),
Node::Restrictions(restrictions) => set_restrictions(restrictions, field, child),
Node::Price(price) => set_price(price, field, child),
Node::V211Tariff(tariff) => set_v211_tariff(tariff, field, child),
Node::V211Element(element) => set_v211_element(element, field, child),
Node::V211PriceComponent(component) => {
set_v211_price_component(component, field, child);
}
Node::V211Restrictions(restrictions) => {
set_v211_restrictions(restrictions, field, child);
}
Node::V211Cdr(cdr) => set_v211_cdr(cdr, field, child),
Node::V211ChargingPeriod(period) => set_v211_charging_period(period, field, child),
Node::V211CdrDimension(dimension) => set_v211_dimension(dimension, field, child),
Node::Ignore
| Node::Str(_)
| Node::Number(_)
| Node::Enum(_)
| Node::Bool
| Node::Array(_) => {}
}
}
fn push(&mut self, item: Integrity<Node<'buf>>) {
if let Node::Array(items) = self {
items.push(item);
}
}
}
pub(super) fn set_top_field<'buf>(
builders: &mut [Node<'buf>],
name: &'static str,
value: Integrity<Node<'buf>>,
) {
if let Some(top) = builders.last_mut() {
top.set(name, value);
}
}
fn set_tariff<'buf>(tariff: &mut v221::Tariff<'buf>, field: &str, child: Integrity<Node<'buf>>) {
match field {
"country_code" => tariff.country_code = as_str(child),
"currency" => tariff.currency = as_str(child),
"id" => tariff.id = as_str(child),
"party_id" => tariff.party_id = as_str(child),
"min_price" => tariff.min_price = as_opt_price(child),
"max_price" => tariff.max_price = as_opt_price(child),
"start_date_time" => tariff.start_date_time = as_opt_str(child),
"end_date_time" => tariff.end_date_time = as_opt_str(child),
"elements" => tariff.elements = as_array(child, as_element),
_ => {}
}
}
fn set_element<'buf>(element: &mut v221::Element<'buf>, field: &str, child: Integrity<Node<'buf>>) {
match field {
"price_components" => element.price_components = as_array(child, as_price_component),
"restrictions" => element.restrictions = as_opt_restrictions(child),
_ => {}
}
}
fn set_price_component<'buf>(
component: &mut v221::PriceComponent<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"type" => component.dimension_type = as_enum(child),
"vat" => component.vat = as_opt_number(child),
"price" => component.price = as_number(child),
"step_size" => component.step_size = as_number(child),
_ => {}
}
}
fn set_restrictions<'buf>(
restrictions: &mut v221::Restrictions<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"start_time" => restrictions.start_time = as_opt_str(child),
"end_time" => restrictions.end_time = as_opt_str(child),
"start_date" => restrictions.start_date = as_opt_str(child),
"end_date" => restrictions.end_date = as_opt_str(child),
"min_kwh" => restrictions.min_kwh = as_opt_number(child),
"max_kwh" => restrictions.max_kwh = as_opt_number(child),
"min_current" => restrictions.min_current = as_opt_number(child),
"max_current" => restrictions.max_current = as_opt_number(child),
"min_power" => restrictions.min_power = as_opt_number(child),
"max_power" => restrictions.max_power = as_opt_number(child),
"min_duration" => restrictions.min_duration = as_opt_number(child),
"max_duration" => restrictions.max_duration = as_opt_number(child),
"day_of_week" => restrictions.day_of_week = as_opt_array(child, as_enum),
"reservation" => restrictions.reservation = as_opt_enum(child),
_ => {}
}
}
fn set_price<'buf>(price: &mut v221::Price<'buf>, field: &str, child: Integrity<Node<'buf>>) {
match field {
"excl_vat" => price.excl_vat = as_number(child),
"incl_vat" => price.incl_vat = as_opt_number(child),
_ => {}
}
}
fn set_cdr<'buf>(cdr: &mut v221::Cdr<'buf>, field: &str, child: Integrity<Node<'buf>>) {
match field {
"currency" => cdr.currency = as_str(child),
"start_date_time" => cdr.start_date_time = as_str(child),
"end_date_time" => cdr.end_date_time = as_str(child),
"charging_periods" => cdr.charging_periods = as_array(child, as_charging_period),
"total_cost" => cdr.total_cost = as_price(child),
"total_energy" => cdr.total_energy = as_number(child),
"total_time" => cdr.total_time = as_number(child),
"total_parking_time" => cdr.total_parking_time = as_opt_number(child),
"total_energy_cost" => cdr.total_energy_cost = as_opt_price(child),
"total_fixed_cost" => cdr.total_fixed_cost = as_opt_price(child),
"total_parking_cost" => cdr.total_parking_cost = as_opt_price(child),
"total_reservation_cost" => cdr.total_reservation_cost = as_opt_price(child),
"total_time_cost" => cdr.total_time_cost = as_opt_price(child),
"tariffs" => cdr.tariffs = as_opt_array(child, as_tariff),
_ => {}
}
}
fn set_charging_period<'buf>(
period: &mut v221::ChargingPeriod<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"start_date_time" => period.start_date_time = as_str(child),
"dimensions" => period.dimensions = as_array(child, as_dimension),
_ => {}
}
}
fn set_dimension<'buf>(
dimension: &mut v221::Dimension<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"type" => dimension.dimension_type = as_enum(child),
"volume" => dimension.volume = as_number(child),
_ => {}
}
}
fn set_v211_tariff<'buf>(
tariff: &mut v211::Tariff<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"currency" => tariff.currency = as_str(child),
"id" => tariff.id = as_str(child),
"elements" => tariff.elements = as_array(child, as_v211_element),
_ => {}
}
}
fn set_v211_element<'buf>(
element: &mut v211::Element<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"price_components" => element.price_components = as_array(child, as_v211_price_component),
"restrictions" => element.restrictions = as_opt_v211_restrictions(child),
_ => {}
}
}
fn set_v211_price_component<'buf>(
component: &mut v211::PriceComponent<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"type" => component.dimension_type = as_enum(child),
"price" => component.price = as_number(child),
"step_size" => component.step_size = as_number(child),
_ => {}
}
}
fn set_v211_restrictions<'buf>(
restrictions: &mut v211::Restrictions<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"start_time" => restrictions.start_time = as_opt_str(child),
"end_time" => restrictions.end_time = as_opt_str(child),
"start_date" => restrictions.start_date = as_opt_str(child),
"end_date" => restrictions.end_date = as_opt_str(child),
"min_kwh" => restrictions.min_kwh = as_opt_number(child),
"max_kwh" => restrictions.max_kwh = as_opt_number(child),
"min_power" => restrictions.min_power = as_opt_number(child),
"max_power" => restrictions.max_power = as_opt_number(child),
"min_duration" => restrictions.min_duration = as_opt_number(child),
"max_duration" => restrictions.max_duration = as_opt_number(child),
"day_of_week" => restrictions.day_of_week = as_opt_array(child, as_enum),
_ => {}
}
}
fn set_v211_cdr<'buf>(cdr: &mut v211::Cdr<'buf>, field: &str, child: Integrity<Node<'buf>>) {
match field {
"currency" => cdr.currency = as_str(child),
"start_date_time" => cdr.start_date_time = as_str(child),
"stop_date_time" => cdr.stop_date_time = as_str(child),
"charging_periods" => cdr.charging_periods = as_array(child, as_v211_charging_period),
"total_cost" => cdr.total_cost = as_number(child),
"total_energy" => cdr.total_energy = as_number(child),
"total_time" => cdr.total_time = as_number(child),
"total_parking_time" => cdr.total_parking_time = as_opt_number(child),
"tariffs" => cdr.tariffs = as_opt_array(child, as_v211_tariff),
_ => {}
}
}
fn set_v211_charging_period<'buf>(
period: &mut v211::ChargingPeriod<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"start_date_time" => period.start_date_time = as_str(child),
"dimensions" => period.dimensions = as_array(child, as_v211_dimension),
_ => {}
}
}
fn set_v211_dimension<'buf>(
dimension: &mut v211::Dimension<'buf>,
field: &str,
child: Integrity<Node<'buf>>,
) {
match field {
"type" => dimension.dimension_type = as_enum(child),
"volume" => dimension.volume = as_number(child),
_ => {}
}
}
macro_rules! extract {
($name:ident, $variant:ident, $ty:ty) => {
fn $name(child: Integrity<Node<'_>>) -> Integrity<$ty> {
match child {
Integrity::Ok(node) => {
if let Node::$variant(value) = node {
Integrity::Ok(value)
} else {
Integrity::Err
}
}
Integrity::Missing => Integrity::Missing,
Integrity::Err => Integrity::Err,
}
}
};
}
macro_rules! extract_opt {
($name:ident, $variant:ident, $ty:ty) => {
fn $name(child: Integrity<Node<'_>>) -> Integrity<Option<$ty>> {
match child {
Integrity::Ok(node) => {
if let Node::$variant(value) = node {
Integrity::Ok(Some(value))
} else {
Integrity::Err
}
}
Integrity::Missing => Integrity::Ok(None),
Integrity::Err => Integrity::Err,
}
}
};
}
extract!(as_str, Str, Str<'_>);
extract!(as_number, Number, Number<'_>);
extract!(as_enum, Enum, Enum<'_>);
extract!(as_price, Price, v221::Price<'_>);
extract!(as_tariff, Tariff, v221::Tariff<'_>);
extract!(as_charging_period, ChargingPeriod, v221::ChargingPeriod<'_>);
extract!(as_dimension, CdrDimension, v221::Dimension<'_>);
extract!(as_element, Element, v221::Element<'_>);
extract!(as_price_component, PriceComponent, v221::PriceComponent<'_>);
extract!(as_v211_element, V211Element, v211::Element<'_>);
extract!(
as_v211_price_component,
V211PriceComponent,
v211::PriceComponent<'_>
);
extract!(as_v211_tariff, V211Tariff, v211::Tariff<'_>);
extract!(
as_v211_charging_period,
V211ChargingPeriod,
v211::ChargingPeriod<'_>
);
extract!(as_v211_dimension, V211CdrDimension, v211::Dimension<'_>);
extract_opt!(as_opt_str, Str, Str<'_>);
extract_opt!(as_opt_number, Number, Number<'_>);
extract_opt!(as_opt_enum, Enum, Enum<'_>);
extract_opt!(as_opt_price, Price, v221::Price<'_>);
extract_opt!(as_opt_restrictions, Restrictions, v221::Restrictions<'_>);
extract_opt!(
as_opt_v211_restrictions,
V211Restrictions,
v211::Restrictions<'_>
);
fn as_array<'buf, T>(
child: Integrity<Node<'buf>>,
f: impl Fn(Integrity<Node<'buf>>) -> Integrity<T>,
) -> Integrity<Vec<Integrity<T>>> {
match child {
Integrity::Ok(node) => {
if let Node::Array(items) = node {
Integrity::Ok(items.into_iter().map(f).collect())
} else {
Integrity::Err
}
}
Integrity::Missing => Integrity::Missing,
Integrity::Err => Integrity::Err,
}
}
fn as_opt_array<'buf, T>(
child: Integrity<Node<'buf>>,
f: impl Fn(Integrity<Node<'buf>>) -> Integrity<T>,
) -> Integrity<Option<Vec<Integrity<T>>>> {
match child {
Integrity::Ok(node) => {
if let Node::Array(items) = node {
Integrity::Ok(Some(items.into_iter().map(f).collect()))
} else {
Integrity::Err
}
}
Integrity::Missing => Integrity::Ok(None),
Integrity::Err => Integrity::Err,
}
}