#[derive(hard_xml::XmlWrite, hard_xml::XmlRead, Default, PartialEq, Clone, Debug)]
#[xml(tag = "TrackingEvents", strict(unknown_attribute, unknown_element))]
pub struct TrackingEvents<'a> {
#[xml(child = "Tracking", default)]
pub trackings: Vec<Tracking<'a>>,
}
#[derive(hard_xml::XmlWrite, hard_xml::XmlRead, PartialEq, Clone, Debug)]
#[xml(tag = "Tracking", strict(unknown_attribute, unknown_element))]
pub struct Tracking<'a> {
#[xml(attr = "event")]
pub event: TrackingEvent,
#[xml(attr = "offset", default)]
pub offset: Option<Offset>,
#[xml(text, cdata, default)]
pub uri: std::borrow::Cow<'a, str>,
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum TrackingEvent {
Mute,
Unmute,
Pause,
Resume,
Rewind,
Skip,
PlayerExpand,
PlayerCollapse,
Loaded,
Start,
FirstQuartile,
MidPoint,
ThirdQuartile,
Complete,
Progress,
CloseLinear,
CreativeView,
AcceptInvitation,
AdExpand,
AdCollapse,
Minimize,
Close,
OverlayViewDuration,
OtherAdInteraction,
InteractiveStart,
}
impl std::str::FromStr for TrackingEvent {
type Err = crate::VastParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"mute" => Self::Mute,
"unmute" => Self::Unmute,
"pause" => Self::Pause,
"resume" => Self::Resume,
"rewind" => Self::Rewind,
"skip" => Self::Skip,
"playerExpand" => Self::PlayerExpand,
"playerCollapse" => Self::PlayerCollapse,
"loaded" => Self::Loaded,
"start" => Self::Start,
"firstQuartile" => Self::FirstQuartile,
"midpoint" => Self::MidPoint,
"thirdQuartile" => Self::ThirdQuartile,
"complete" => Self::Complete,
"progress" => Self::Progress,
"closeLinear" => Self::CloseLinear,
"creativeView" => Self::CreativeView,
"acceptInvitation" => Self::AcceptInvitation,
"adExpand" => Self::AdExpand,
"adCollapse" => Self::AdCollapse,
"minimize" => Self::Minimize,
"close" => Self::Close,
"overlayViewDuration" => Self::OverlayViewDuration,
"otherAdInteraction" => Self::OtherAdInteraction,
"interactiveStart" => Self::InteractiveStart,
_ => {
return Err(crate::VastParseError::new(format!(
"tracking event parsing error: '{s}'",
)));
}
})
}
}
impl std::fmt::Display for TrackingEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mute => write!(f, "mute"),
Self::Unmute => write!(f, "unmute"),
Self::Pause => write!(f, "pause"),
Self::Resume => write!(f, "resume"),
Self::Rewind => write!(f, "rewind"),
Self::Skip => write!(f, "skip"),
Self::PlayerExpand => write!(f, "playerExpand"),
Self::PlayerCollapse => write!(f, "playerCollapse"),
Self::Loaded => write!(f, "loaded"),
Self::Start => write!(f, "start"),
Self::FirstQuartile => write!(f, "firstQuartile"),
Self::MidPoint => write!(f, "midpoint"),
Self::ThirdQuartile => write!(f, "thirdQuartile"),
Self::Complete => write!(f, "complete"),
Self::Progress => write!(f, "progress"),
Self::CloseLinear => write!(f, "closeLinear"),
Self::CreativeView => write!(f, "creativeView"),
Self::AcceptInvitation => write!(f, "acceptInvitation"),
Self::AdExpand => write!(f, "adExpand"),
Self::AdCollapse => write!(f, "adCollapse"),
Self::Minimize => write!(f, "minimize"),
Self::Close => write!(f, "close"),
Self::OverlayViewDuration => write!(f, "overlayViewDuration"),
Self::OtherAdInteraction => write!(f, "otherAdInteraction"),
Self::InteractiveStart => write!(f, "interactiveStart"),
}
}
}
#[derive(PartialEq, Clone, Debug)]
pub enum Offset {
Duration(crate::Duration),
Percentage(i32),
}
impl std::str::FromStr for Offset {
type Err = crate::VastParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let trimed = s.trim();
if let Some((head, "")) = trimed.split_once('%') {
let offset = head.parse::<i32>().map_err(|_| {
crate::VastParseError::new(format!("offset value parsing error: '{s}'"))
})?;
return Ok(Self::Percentage(offset));
}
Ok(Self::Duration(s.parse::<crate::Duration>()?))
}
}
impl std::fmt::Display for Offset {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Offset::Duration(dur) => write!(f, "{dur}"),
Offset::Percentage(per) => write!(f, "{per}%"),
}
}
}
crate::declare_test!(
test_tracking_events,
TrackingEvents,
"<TrackingEvents>\
<Tracking event=\"mute\"><![CDATA[https://hoge.com/fuga?mute]]></Tracking>\
<Tracking event=\"progress\" offset=\"00:00:10\"><![CDATA[https://hoge.com/fuga?offset=10]]></Tracking>\
<Tracking event=\"progress\" offset=\"20%\"><![CDATA[https://hoge.com/fuga?offset=20-per]]></Tracking>\
</TrackingEvents>",
TrackingEvents {
trackings: vec![
Tracking {
event: TrackingEvent::Mute,
uri: "https://hoge.com/fuga?mute".into(),
offset: Default::default(),
},
Tracking {
event: TrackingEvent::Progress,
offset: Some(crate::Offset::Duration(crate::Duration::new(00, 00, 10, 000))),
uri: "https://hoge.com/fuga?offset=10".into(),
},
Tracking {
event: TrackingEvent::Progress,
offset: Some(crate::Offset::Percentage(20)),
uri: "https://hoge.com/fuga?offset=20-per".into(),
}
]
}
);