use super::{
document::{OwnedName, ParameterInit, PrintFeatureOption, NS_PSK},
FeatureOptionPack, FeatureOptionPackWithPredefined, PredefinedInputBin, PrintCapabilities,
};
#[derive(Clone, Debug)]
pub struct InputBin {
feature_path: &'static [OwnedName],
option: PrintFeatureOption,
parameters: Vec<ParameterInit>,
}
impl InputBin {
fn feature_paths() -> &'static [Vec<OwnedName>; 3] {
static PATHS: std::sync::LazyLock<[Vec<OwnedName>; 3]> = std::sync::LazyLock::new(|| {
["JobInputBin", "DocumentInputBin", "PageInputBin"]
.map(|name| vec![OwnedName::qualified(name, NS_PSK, Some("psk"))])
});
&PATHS
}
pub fn list(capabilities: &PrintCapabilities) -> impl Iterator<Item = Self> + '_ {
Self::feature_paths()
.iter()
.find_map(|feature_path| {
let mut options = capabilities.options_for_feature(feature_path).peekable();
options.peek().is_some().then_some((feature_path, options))
})
.into_iter()
.flat_map(move |(feature_path, options)| {
options.map(move |option| Self {
feature_path,
option: option.clone(),
parameters: capabilities.default_parameters_for_option(option),
})
})
}
}
impl FeatureOptionPack for InputBin {
fn option_feature_path(&self) -> &[OwnedName] {
self.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 FeatureOptionPackWithPredefined for InputBin {
type PredefinedName = PredefinedInputBin;
}
#[cfg(test)]
mod tests {
use crate::{
test_utils::null_device,
ticket::{
document::{OwnedName, NS_PSK},
test_helpers::{assert_converted, assert_merged, capabilities_with_features},
FeatureOptionPack, FeatureOptionPackWithPredefined, PredefinedInputBin,
PrintCapabilities,
},
};
#[test]
fn use_auto_select() {
let device = null_device::thread_local();
let capabilities = PrintCapabilities::fetch(&device).unwrap();
let auto_select = capabilities
.input_bins()
.find(|x| x.as_predefined_name() == Some(PredefinedInputBin::AutoSelect))
.unwrap();
assert_merged(&device, auto_select);
}
#[test]
fn input_bins_prefer_the_widest_scope() {
let capabilities = capabilities_with_features(
r#" <psf:Feature name="psk:JobInputBin">
<psf:Option name="psk:Cassette" />
</psf:Feature>
<psf:Feature name="psk:DocumentInputBin">
<psf:Option name="psk:Manual" />
<psf:Option name="psk:Tractor" />
</psf:Feature>
<psf:Feature name="psk:PageInputBin">
<psf:Option name="psk:AutoSheetFeeder" />
</psf:Feature>"#,
);
let bins = capabilities.input_bins().collect::<Vec<_>>();
assert_eq!(bins.len(), 1);
assert_eq!(
bins[0].as_predefined_name(),
Some(PredefinedInputBin::Cassette)
);
assert_eq!(
bins[0].option_feature_path(),
vec![OwnedName::qualified("JobInputBin", NS_PSK, Some("psk"))]
);
}
#[test]
fn input_bins_fall_back_to_narrower_scopes_only_when_needed() {
let capabilities = capabilities_with_features(
r#" <psf:Feature name="psk:DocumentInputBin">
<psf:Option name="psk:Manual" />
<psf:Option name="psk:Tractor" />
</psf:Feature>
<psf:Feature name="psk:PageInputBin">
<psf:Option name="psk:AutoSheetFeeder" />
</psf:Feature>"#,
);
let bins = capabilities.input_bins().collect::<Vec<_>>();
assert_eq!(
bins.iter()
.map(|x| x.as_predefined_name())
.collect::<Vec<_>>(),
vec![
Some(PredefinedInputBin::Manual),
Some(PredefinedInputBin::Tractor)
]
);
let document_input_bin = vec![OwnedName::qualified(
"DocumentInputBin",
NS_PSK,
Some("psk"),
)];
assert!(bins
.iter()
.all(|x| x.option_feature_path() == document_input_bin));
bins.into_iter().for_each(assert_converted);
let capabilities = capabilities_with_features(
r#" <psf:Feature name="psk:PageInputBin">
<psf:Option name="psk:AutoSheetFeeder" />
</psf:Feature>"#,
);
assert_eq!(
capabilities
.input_bins()
.map(|x| x.as_predefined_name())
.collect::<Vec<_>>(),
vec![Some(PredefinedInputBin::AutoSheetFeeder)]
);
}
}