use std::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use time::OffsetDateTime;
use time::format_description::well_known::Rfc3339;
use crate::RedispatchXmlError;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DocumentId(String);
impl DocumentId {
#[must_use = "this returns the new DocumentId, discarding it is likely a mistake"]
pub fn new(s: impl Into<String>) -> Result<Self, RedispatchXmlError> {
let s = s.into();
if s.is_empty() || s.len() > 35 {
return Err(RedispatchXmlError::InvalidDocumentId(s));
}
Ok(Self(s))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for DocumentId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for DocumentId {
type Error = RedispatchXmlError;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::new(s)
}
}
impl TryFrom<&str> for DocumentId {
type Error = RedispatchXmlError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::new(s)
}
}
impl fmt::Display for DocumentId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'de> Deserialize<'de> for DocumentId {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
Self::new(s).map_err(serde::de::Error::custom)
}
}
impl Serialize for DocumentId {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}
pub type Mrid = DocumentId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DocumentVersion(u16);
impl DocumentVersion {
#[must_use = "this returns the new DocumentVersion, discarding it is likely a mistake"]
pub fn new(v: u32) -> Result<Self, RedispatchXmlError> {
if v == 0 || v > 999 {
return Err(RedispatchXmlError::InvalidDocumentVersion(v));
}
Ok(Self(v as u16))
}
pub fn get(self) -> u16 {
self.0
}
}
impl fmt::Display for DocumentVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'de> Deserialize<'de> for DocumentVersion {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let v: u32 = Deserialize::deserialize(d)?;
Self::new(v).map_err(serde::de::Error::custom)
}
}
impl Serialize for DocumentVersion {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}
pub type RevisionNumber = DocumentVersion;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct UtcDateTime(OffsetDateTime);
impl UtcDateTime {
#[must_use = "this returns the new UtcDateTime, discarding it is likely a mistake"]
pub fn new(dt: OffsetDateTime) -> Result<Self, RedispatchXmlError> {
if dt.offset() != time::UtcOffset::UTC {
return Err(RedispatchXmlError::InvalidTimestamp(dt.to_string()));
}
Ok(Self(dt))
}
pub fn inner(self) -> OffsetDateTime {
self.0
}
}
impl<'de> Deserialize<'de> for UtcDateTime {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
let dt = OffsetDateTime::parse(&s, &Rfc3339)
.map_err(|_| serde::de::Error::custom(format!("invalid UTC timestamp: {s:?}")))?;
if dt.offset() != time::UtcOffset::UTC {
return Err(serde::de::Error::custom(format!(
"timestamp must use UTC (Z suffix): {s:?}"
)));
}
Ok(UtcDateTime(dt))
}
}
impl Serialize for UtcDateTime {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0
.format(&Rfc3339)
.map_err(serde::ser::Error::custom)?
.serialize(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct UtcMinuteDateTime(OffsetDateTime);
impl UtcMinuteDateTime {
#[must_use = "this returns the new UtcMinuteDateTime, discarding it is likely a mistake"]
pub fn new(dt: OffsetDateTime) -> Result<Self, RedispatchXmlError> {
if dt.offset() != time::UtcOffset::UTC {
return Err(RedispatchXmlError::InvalidTimestamp(dt.to_string()));
}
Ok(Self(dt))
}
pub fn inner(self) -> OffsetDateTime {
self.0
}
}
const MINUTE_FMT: &[time::format_description::BorrowedFormatItem<'static>] =
time::macros::format_description!("[year]-[month]-[day]T[hour]:[minute]Z");
impl<'de> Deserialize<'de> for UtcMinuteDateTime {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
let naive = time::PrimitiveDateTime::parse(&s, MINUTE_FMT).map_err(|_| {
serde::de::Error::custom(format!("invalid UTC minute timestamp: {s:?}"))
})?;
Ok(UtcMinuteDateTime(naive.assume_offset(time::UtcOffset::UTC)))
}
}
impl Serialize for UtcMinuteDateTime {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0
.format(MINUTE_FMT)
.map_err(serde::ser::Error::custom)?
.serialize(s)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TimeInterval {
pub start: OffsetDateTime,
pub end: OffsetDateTime,
}
impl TimeInterval {
#[must_use = "this returns the new TimeInterval, discarding it is likely a mistake"]
pub fn new(start: OffsetDateTime, end: OffsetDateTime) -> Result<Self, RedispatchXmlError> {
if start.offset() != time::UtcOffset::UTC || end.offset() != time::UtcOffset::UTC {
return Err(RedispatchXmlError::InvalidTimeInterval(
"timestamps must be UTC".into(),
));
}
if start >= end {
return Err(RedispatchXmlError::InvalidTimeInterval(
"start must be before end".into(),
));
}
Ok(Self { start, end })
}
}
impl<'de> Deserialize<'de> for TimeInterval {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
let (start_str, end_str) = s.split_once('/').ok_or_else(|| {
serde::de::Error::custom(format!("invalid time interval {s:?}: missing '/'"))
})?;
let start_naive = time::PrimitiveDateTime::parse(start_str, MINUTE_FMT).map_err(|_| {
serde::de::Error::custom(format!("invalid interval start {start_str:?}"))
})?;
let end_naive = time::PrimitiveDateTime::parse(end_str, MINUTE_FMT)
.map_err(|_| serde::de::Error::custom(format!("invalid interval end {end_str:?}")))?;
Ok(TimeInterval {
start: start_naive.assume_offset(time::UtcOffset::UTC),
end: end_naive.assume_offset(time::UtcOffset::UTC),
})
}
}
impl Serialize for TimeInterval {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let start = self
.start
.format(MINUTE_FMT)
.map_err(serde::ser::Error::custom)?;
let end = self
.end
.format(MINUTE_FMT)
.map_err(serde::ser::Error::custom)?;
format!("{start}/{end}").serialize(s)
}
}
impl fmt::Display for TimeInterval {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let start = self.start.format(MINUTE_FMT).map_err(|_| fmt::Error)?;
let end = self.end.format(MINUTE_FMT).map_err(|_| fmt::Error)?;
write!(f, "{start}/{end}")
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MarketParticipantId(String);
impl MarketParticipantId {
#[must_use = "this returns the new MarketParticipantId, discarding it is likely a mistake"]
pub fn new(s: impl Into<String>) -> Result<Self, RedispatchXmlError> {
let s = s.into();
if s.len() != 13 || !s.chars().all(|c| c.is_ascii_digit()) {
return Err(RedispatchXmlError::InvalidMarketParticipantId(s));
}
Ok(Self(s))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for MarketParticipantId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for MarketParticipantId {
type Error = RedispatchXmlError;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::new(s)
}
}
impl TryFrom<&str> for MarketParticipantId {
type Error = RedispatchXmlError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::new(s)
}
}
impl fmt::Display for MarketParticipantId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'de> Deserialize<'de> for MarketParticipantId {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
Self::new(s).map_err(serde::de::Error::custom)
}
}
impl Serialize for MarketParticipantId {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Decimal3(f64);
impl Decimal3 {
#[must_use = "this returns the new Decimal3, discarding it is likely a mistake"]
pub fn new(v: f64) -> Result<Self, RedispatchXmlError> {
if v < 0.0 {
return Err(RedispatchXmlError::StructuralError(format!(
"Decimal3 value {v} must be ≥ 0"
)));
}
Ok(Self(v))
}
pub fn value(self) -> f64 {
self.0
}
}
impl<'de> Deserialize<'de> for Decimal3 {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let v: f64 = Deserialize::deserialize(d)?;
Self::new(v).map_err(serde::de::Error::custom)
}
}
impl Serialize for Decimal3 {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
format!("{:.3}", self.0).serialize(s)
}
}
impl fmt::Display for Decimal3 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.3}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CodingScheme {
#[serde(rename = "A10")]
Gs1,
#[serde(rename = "NDE")]
Nde,
#[serde(rename = "A01")]
Eic,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum MeasureUnit {
#[serde(rename = "MAW")]
Megawatt,
#[serde(rename = "P1")]
Percent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Direction {
#[serde(rename = "A01")]
Up,
#[serde(rename = "A02")]
Down,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum MarketRoleType {
#[serde(rename = "A08")]
BalanceResponsibleParty,
#[serde(rename = "A18")]
GridOperator,
#[serde(rename = "A21")]
Producer,
#[serde(rename = "A27")]
ResourceProvider,
#[serde(rename = "A39")]
DataProvider,
#[serde(rename = "Z01")]
Supplier,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ControlZone {
#[serde(rename = "10YDE-ENBW-----N")]
TransnetBw,
#[serde(rename = "10YDE-EON------1")]
TennetDe,
#[serde(rename = "10YDE-RWENET---I")]
Amprion,
#[serde(rename = "10YDE-VE-------2")]
FiftyHertz,
#[serde(rename = "10YFLENSBURG---3")]
Flensburg,
#[serde(rename = "11YRBAHNSTROM--P")]
Bahnstrom,
}