use std::{
borrow::Cow,
path::{Path, PathBuf},
};
pub use crate::safe_mode::SafeMode;
use crate::{
AttributeValue, DocumentAttributes, Error,
document_attribute::{InputKind, initialize_configuration, initialize_intrinsics},
model::RawAttributes,
};
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct Options<'a> {
pub safe_mode: SafeMode,
pub timings: bool,
pub(crate) document_attributes: DocumentAttributes<'a>,
pub base_dir: Option<PathBuf>,
pub strict: bool,
#[cfg(feature = "setext")]
pub setext: bool,
}
impl<'a> Options<'a> {
#[must_use]
pub fn builder() -> OptionsBuilder<'a> {
OptionsBuilder::default()
}
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn with_attributes<N, V>(
attributes: impl IntoIterator<Item = (N, V)>,
) -> Result<Self, Error>
where
N: Into<Cow<'a, str>>,
V: Into<AttributeValue<'a>>,
{
Self::builder().with_attributes(attributes).build()
}
#[must_use]
pub const fn document_attributes(&self) -> &DocumentAttributes<'a> {
&self.document_attributes
}
#[must_use]
pub fn into_document_attributes(self) -> DocumentAttributes<'a> {
self.document_attributes
}
#[must_use]
pub fn with_document_attributes(mut self, attributes: DocumentAttributes<'a>) -> Self {
self.document_attributes = attributes;
self
}
#[must_use]
pub fn into_builder(self) -> OptionsBuilder<'a> {
let (attributes, defaults) = self.document_attributes.into_configuration();
OptionsBuilder {
attributes,
defaults,
safe_mode: self.safe_mode,
timings: self.timings,
base_dir: self.base_dir,
strict: self.strict,
#[cfg(feature = "setext")]
setext: self.setext,
}
}
pub(crate) fn prepare_for_parse(mut self, input_kind: InputKind<'_>) -> Self {
initialize_intrinsics(&mut self.document_attributes, self.safe_mode, input_kind);
self
}
#[must_use]
pub fn into_static(self) -> Options<'static> {
Options {
safe_mode: self.safe_mode,
timings: self.timings,
document_attributes: self.document_attributes.into_static(),
base_dir: self.base_dir,
strict: self.strict,
#[cfg(feature = "setext")]
setext: self.setext,
}
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct OptionsBuilder<'a> {
safe_mode: SafeMode,
timings: bool,
attributes: RawAttributes<'a>,
defaults: RawAttributes<'a>,
base_dir: Option<PathBuf>,
strict: bool,
#[cfg(feature = "setext")]
setext: bool,
}
impl<'a> OptionsBuilder<'a> {
#[must_use]
pub fn with_safe_mode(mut self, safe_mode: SafeMode) -> Self {
self.safe_mode = safe_mode;
self
}
#[must_use]
pub fn with_timings(mut self) -> Self {
self.timings = true;
self
}
#[must_use]
pub fn with_base_dir(mut self, base_dir: impl AsRef<Path>) -> Self {
self.base_dir = Some(base_dir.as_ref().to_path_buf());
self
}
#[must_use]
pub fn with_strict(mut self) -> Self {
self.strict = true;
self
}
#[must_use]
pub fn with_attribute(
mut self,
name: impl Into<Cow<'a, str>>,
value: impl Into<AttributeValue<'a>>,
) -> Self {
self.attributes.insert(name.into(), value.into());
self
}
#[must_use]
pub fn with_attributes<N, V>(mut self, attributes: impl IntoIterator<Item = (N, V)>) -> Self
where
N: Into<Cow<'a, str>>,
V: Into<AttributeValue<'a>>,
{
self.attributes = attributes
.into_iter()
.map(|(name, value)| (name.into(), value.into()))
.collect();
self
}
#[must_use]
pub fn with_defaults<N, V>(mut self, defaults: impl IntoIterator<Item = (N, V)>) -> Self
where
N: Into<Cow<'a, str>>,
V: Into<AttributeValue<'a>>,
{
self.defaults = defaults
.into_iter()
.map(|(name, value)| (name.into(), value.into()))
.collect();
self
}
#[must_use]
pub fn with_default_attribute(
mut self,
name: impl Into<Cow<'a, str>>,
value: impl Into<AttributeValue<'a>>,
) -> Self {
self.defaults.insert(name.into(), value.into());
self
}
#[must_use]
pub fn attribute(&self, name: &str) -> Option<&AttributeValue<'a>> {
self.attributes
.get(name)
.or_else(|| self.defaults.get(name))
}
#[cfg(feature = "setext")]
#[must_use]
pub fn with_setext(mut self) -> Self {
self.setext = true;
self
}
pub fn build(self) -> Result<Options<'a>, Error> {
let document_attributes = initialize_configuration(self.attributes, self.defaults)?;
Ok(Options {
safe_mode: self.safe_mode,
timings: self.timings,
document_attributes,
base_dir: self.base_dir,
strict: self.strict,
#[cfg(feature = "setext")]
setext: self.setext,
})
}
}