use xml::name::OwnedName;
use super::{
document::{
ParameterInit, PrintFeature, PrintFeatureOption, PrintTicketDocument, WithProperties,
NS_PSK,
},
PrintCapabilities, PrintTicket,
};
pub trait PredefinedName: Sized {
fn from_name(name: &OwnedName) -> Option<Self>;
}
pub trait FeatureOptionPack: Sized {
fn option_feature_path(&self) -> &[OwnedName];
fn option(&self) -> &PrintFeatureOption;
fn option_mut(&mut self) -> &mut PrintFeatureOption;
fn parameters(&self) -> &[ParameterInit];
fn parameters_mut(&mut self) -> &mut Vec<ParameterInit>;
fn into_option_with_parameters(self) -> (PrintFeatureOption, Vec<ParameterInit>);
fn display_name(&self) -> Option<&str> {
self.option()
.get_property("DisplayName", Some(NS_PSK))
.and_then(|x| x.value.as_ref())
.and_then(|x| x.string())
}
}
pub trait StaticFeaturePathOptionPack: FeatureOptionPack {
fn new(option: PrintFeatureOption, parameters: Vec<ParameterInit>) -> Self;
fn feature_path() -> &'static [OwnedName];
fn from_option(capabilities: &PrintCapabilities, option: &PrintFeatureOption) -> Self {
Self::new(
option.clone(),
capabilities.default_parameters_for_option(option),
)
}
fn list(capabilities: &PrintCapabilities) -> impl Iterator<Item = Self> + '_ {
capabilities
.options_for_feature(Self::feature_path())
.map(|option| Self::from_option(capabilities, option))
}
}
impl<T> From<T> for PrintTicket
where
T: FeatureOptionPack,
{
fn from(value: T) -> Self {
let feature_path = value.option_feature_path().to_vec();
let (option, parameters) = value.into_option_with_parameters();
let features = feature_path
.split_last()
.map(|(leaf, ancestors)| {
ancestors.iter().rev().fold(
PrintFeature {
name: leaf.clone(),
properties: vec![],
options: vec![option],
features: vec![],
},
|feature, name| PrintFeature {
name: name.clone(),
properties: vec![],
options: vec![],
features: vec![feature],
},
)
})
.into_iter()
.collect();
PrintTicketDocument {
properties: vec![],
parameter_inits: parameters,
features,
}
.into()
}
}
pub trait FeatureOptionPackWithPredefined: FeatureOptionPack {
type PredefinedName: PredefinedName;
fn as_predefined_name(&self) -> Option<Self::PredefinedName> {
self.option()
.name
.as_ref()
.and_then(Self::PredefinedName::from_name)
}
}
macro_rules! define_feature_option_pack {
($feature_path:expr, $name:ident) => {
#[derive(Clone, Debug)]
#[doc = concat!("Represents a feature option pack as [`", stringify!($name), "`].")]
pub struct $name {
/// The option of the feature.
option: PrintFeatureOption,
parameters: Vec<ParameterInit>,
}
impl crate::ticket::FeatureOptionPack for $name {
fn option_feature_path(&self) -> &[xml::name::OwnedName] {
<Self as crate::ticket::StaticFeaturePathOptionPack>::feature_path()
}
fn option(&self) -> &PrintFeatureOption {
&self.option
}
fn option_mut(&mut self) -> &mut PrintFeatureOption {
&mut self.option
}
fn parameters(&self) -> &[ParameterInit] {
&self.parameters
}
fn parameters_mut(&mut self) -> &mut Vec<ParameterInit> {
&mut self.parameters
}
fn into_option_with_parameters(self) -> (PrintFeatureOption, Vec<ParameterInit>) {
(self.option, self.parameters)
}
}
impl crate::ticket::StaticFeaturePathOptionPack for $name {
fn new(option: PrintFeatureOption, parameters: Vec<ParameterInit>) -> Self {
Self { option, parameters }
}
fn feature_path() -> &'static [xml::name::OwnedName] {
static PATH: std::sync::LazyLock<Vec<xml::name::OwnedName>> =
std::sync::LazyLock::new(|| $feature_path);
&PATH
}
}
};
($feature_path:expr, $name:ident, $predefined_name:ident) => {
define_feature_option_pack!($feature_path, $name);
impl crate::ticket::FeatureOptionPackWithPredefined for $name {
type PredefinedName = $predefined_name;
}
};
}
pub(crate) use define_feature_option_pack;