#![doc(html_root_url = "https://docs.rs/spreadsheet-ods/0.4.0")]
#![warn(absolute_paths_not_starting_with_crate)]
#![warn(elided_lifetimes_in_paths)]
#![warn(explicit_outlives_requirements)]
#![warn(keyword_idents)]
#![warn(macro_use_extern_crate)]
#![warn(meta_variable_misuse)]
#![warn(missing_abi)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(non_ascii_idents)]
#![warn(noop_method_call)]
#![warn(pointer_structural_match)]
#![warn(semicolon_in_expressions_from_macros)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unreachable_pub)]
#![warn(unsafe_op_in_unsafe_fn)]
#![warn(unstable_features)]
#![warn(unused_import_braces)]
#![warn(unused_lifetimes)]
#![warn(unused_qualifications)]
#![warn(variant_size_differences)]
pub use crate::error::OdsError;
pub use crate::format::{
ValueFormatBoolean, ValueFormatCurrency, ValueFormatDateTime, ValueFormatNumber,
ValueFormatPercentage, ValueFormatRef, ValueFormatText, ValueFormatTimeDuration,
};
pub use crate::io::read::{read_ods, read_ods_buf};
pub use crate::io::write::{write_ods, write_ods_buf, write_ods_buf_uncompressed};
pub use crate::refs::{CellRange, CellRef, ColRange, RowRange};
pub use crate::style::units::{Angle, Length};
pub use crate::style::{CellStyle, CellStyleRef};
use crate::config::Config;
use crate::defaultstyles::{DefaultFormat, DefaultStyle};
use crate::ds::detach::Detach;
use crate::ds::detach::Detached;
use crate::format::ValueFormatTrait;
use crate::io::filebuf::FileBuf;
use crate::io::read::default_settings;
use crate::style::{
ColStyle, ColStyleRef, FontFaceDecl, GraphicStyle, GraphicStyleRef, MasterPage, MasterPageRef,
PageStyle, PageStyleRef, ParagraphStyle, ParagraphStyleRef, RowStyle, RowStyleRef, TableStyle,
TableStyleRef, TextStyle, TextStyleRef,
};
use crate::text::TextTag;
use crate::validation::{Validation, ValidationRef};
use crate::xmltree::XmlTag;
use chrono::{Duration, NaiveTime};
use chrono::{NaiveDate, NaiveDateTime};
use icu_locid::Locale;
#[cfg(feature = "use_decimal")]
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
#[cfg(feature = "use_decimal")]
use rust_decimal::Decimal;
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::iter::FusedIterator;
use std::ops::RangeBounds;
#[macro_use]
mod attr_macro;
#[macro_use]
mod unit_macro;
#[macro_use]
mod format_macro;
#[macro_use]
mod style_macro;
#[macro_use]
mod text_macro;
mod attrmap2;
mod config;
mod ds;
mod io;
mod locale;
pub mod condition;
pub mod defaultstyles;
pub mod error;
pub mod format;
pub mod formula;
pub mod refs;
mod refs_impl;
pub mod style;
pub mod text;
pub mod validation;
pub mod xmltree;
#[derive(Clone, Default)]
pub struct WorkBook {
sheets: Vec<Detach<Sheet>>,
version: String,
fonts: HashMap<String, FontFaceDecl>,
autonum: HashMap<String, u32>,
tablestyles: HashMap<String, TableStyle>,
rowstyles: HashMap<String, RowStyle>,
colstyles: HashMap<String, ColStyle>,
cellstyles: HashMap<String, CellStyle>,
paragraphstyles: HashMap<String, ParagraphStyle>,
textstyles: HashMap<String, TextStyle>,
graphicstyles: HashMap<String, GraphicStyle>,
formats_boolean: HashMap<String, ValueFormatBoolean>,
formats_number: HashMap<String, ValueFormatNumber>,
formats_percentage: HashMap<String, ValueFormatPercentage>,
formats_currency: HashMap<String, ValueFormatCurrency>,
formats_text: HashMap<String, ValueFormatText>,
formats_datetime: HashMap<String, ValueFormatDateTime>,
formats_timeduration: HashMap<String, ValueFormatTimeDuration>,
def_styles: HashMap<ValueType, String>,
pagestyles: HashMap<String, PageStyle>,
masterpages: HashMap<String, MasterPage>,
validations: HashMap<String, Validation>,
config: Detach<Config>,
workbook_config: WorkBookConfig,
filebuf: FileBuf,
extra: Vec<XmlTag>,
}
impl fmt::Debug for WorkBook {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self.version)?;
for s in self.sheets.iter() {
writeln!(f, "{:?}", s)?;
}
for s in self.fonts.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.tablestyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.rowstyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.colstyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.cellstyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.paragraphstyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.graphicstyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_boolean.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_number.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_percentage.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_currency.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_text.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_datetime.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats_timeduration.values() {
writeln!(f, "{:?}", s)?;
}
for (t, s) in &self.def_styles {
writeln!(f, "{:?} -> {:?}", t, s)?;
}
for s in self.pagestyles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.masterpages.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.validations.values() {
writeln!(f, "{:?}", s)?;
}
for xtr in &self.extra {
writeln!(f, "extras {:?}", xtr)?;
}
writeln!(f, "{:#?}", self.filebuf)?;
Ok(())
}
}
fn auto_style_name<T>(
autonum: &mut HashMap<String, u32>,
prefix: &str,
styles: &HashMap<String, T>,
) -> String {
let mut cnt = if let Some(n) = autonum.get(prefix) {
n + 1
} else {
0
};
let style_name = loop {
let style_name = format!("{}{}", prefix, cnt);
if !styles.contains_key(&style_name) {
break style_name;
}
cnt += 1;
};
autonum.insert(prefix.to_string(), cnt);
style_name
}
impl WorkBook {
pub fn new_empty() -> Self {
WorkBook {
sheets: Default::default(),
version: "1.3".to_string(),
fonts: Default::default(),
autonum: Default::default(),
tablestyles: Default::default(),
rowstyles: Default::default(),
colstyles: Default::default(),
cellstyles: Default::default(),
paragraphstyles: Default::default(),
textstyles: Default::default(),
graphicstyles: Default::default(),
formats_boolean: Default::default(),
formats_number: Default::default(),
formats_percentage: Default::default(),
formats_currency: Default::default(),
formats_text: Default::default(),
formats_datetime: Default::default(),
formats_timeduration: Default::default(),
def_styles: Default::default(),
pagestyles: Default::default(),
masterpages: Default::default(),
validations: Default::default(),
config: default_settings(),
workbook_config: Default::default(),
extra: vec![],
filebuf: Default::default(),
}
}
pub fn new(locale: Locale) -> Self {
let mut wb = WorkBook::new_empty();
wb.locale_settings(locale);
wb
}
pub fn locale_settings(&mut self, locale: Locale) {
if let Some(lf) = locale::localized_format(locale) {
self.add_boolean_format(lf.boolean_format());
self.add_number_format(lf.number_format());
self.add_percentage_format(lf.percentage_format());
self.add_currency_format(lf.currency_format());
self.add_datetime_format(lf.date_format());
self.add_datetime_format(lf.datetime_format());
self.add_datetime_format(lf.time_of_day_format());
self.add_timeduration_format(lf.time_interval_format());
}
self.add_cellstyle(CellStyle::new(
DefaultStyle::bool().to_string(),
&DefaultFormat::bool(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::number().to_string(),
&DefaultFormat::number(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::percent().to_string(),
&DefaultFormat::percent(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::currency().to_string(),
&DefaultFormat::currency(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::date().to_string(),
&DefaultFormat::date(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::datetime().to_string(),
&DefaultFormat::datetime(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::time_of_day().to_string(),
&DefaultFormat::time_of_day(),
));
self.add_cellstyle(CellStyle::new(
DefaultStyle::time_interval().to_string(),
&DefaultFormat::time_interval(),
));
self.add_def_style(ValueType::Boolean, &DefaultStyle::bool());
self.add_def_style(ValueType::Number, &DefaultStyle::number());
self.add_def_style(ValueType::Percentage, &DefaultStyle::percent());
self.add_def_style(ValueType::Currency, &DefaultStyle::currency());
self.add_def_style(ValueType::DateTime, &DefaultStyle::date());
self.add_def_style(ValueType::TimeDuration, &DefaultStyle::time_interval());
}
pub fn version(&self) -> &String {
&self.version
}
pub fn set_version(&mut self, version: String) {
self.version = version;
}
pub fn config(&self) -> &WorkBookConfig {
&self.workbook_config
}
pub fn config_mut(&mut self) -> &mut WorkBookConfig {
&mut self.workbook_config
}
pub fn num_sheets(&self) -> usize {
self.sheets.len()
}
pub fn sheet_idx<S: AsRef<str>>(&self, name: S) -> Option<usize> {
for (idx, sheet) in self.sheets.iter().enumerate() {
if sheet.name == name.as_ref() {
return Some(idx);
}
}
None
}
pub fn detach_sheet(&mut self, n: usize) -> Detached<usize, Sheet> {
self.sheets[n].detach(n)
}
pub fn attach_sheet(&mut self, sheet: Detached<usize, Sheet>) {
self.sheets[Detached::key(&sheet)].attach(sheet)
}
pub fn sheet(&self, n: usize) -> &Sheet {
self.sheets[n].as_ref()
}
pub fn sheet_mut(&mut self, n: usize) -> &mut Sheet {
self.sheets[n].as_mut()
}
pub fn insert_sheet(&mut self, i: usize, sheet: Sheet) {
self.sheets.insert(i, sheet.into());
}
pub fn push_sheet(&mut self, sheet: Sheet) {
self.sheets.push(sheet.into());
}
pub fn remove_sheet(&mut self, n: usize) -> Sheet {
self.sheets.remove(n).take()
}
pub fn add_def_style(&mut self, value_type: ValueType, style: &CellStyleRef) {
self.def_styles.insert(value_type, style.to_string());
}
pub fn def_style(&self, value_type: ValueType) -> Option<&String> {
self.def_styles.get(&value_type)
}
pub fn add_font(&mut self, font: FontFaceDecl) {
self.fonts.insert(font.name().to_string(), font);
}
pub fn remove_font(&mut self, name: &str) -> Option<FontFaceDecl> {
self.fonts.remove(name)
}
pub fn font(&self, name: &str) -> Option<&FontFaceDecl> {
self.fonts.get(name)
}
pub fn font_mut(&mut self, name: &str) -> Option<&mut FontFaceDecl> {
self.fonts.get_mut(name)
}
pub fn add_tablestyle(&mut self, mut style: TableStyle) -> TableStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(&mut self.autonum, "ta", &self.tablestyles));
}
let sref = style.style_ref();
self.tablestyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_tablestyle(&mut self, name: &str) -> Option<TableStyle> {
self.tablestyles.remove(name)
}
pub fn tablestyle(&self, name: &str) -> Option<&TableStyle> {
self.tablestyles.get(name)
}
pub fn tablestyle_mut(&mut self, name: &str) -> Option<&mut TableStyle> {
self.tablestyles.get_mut(name)
}
pub fn add_rowstyle(&mut self, mut style: RowStyle) -> RowStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(&mut self.autonum, "ro", &self.rowstyles));
}
let sref = style.style_ref();
self.rowstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_rowstyle(&mut self, name: &str) -> Option<RowStyle> {
self.rowstyles.remove(name)
}
pub fn rowstyle(&self, name: &str) -> Option<&RowStyle> {
self.rowstyles.get(name)
}
pub fn rowstyle_mut(&mut self, name: &str) -> Option<&mut RowStyle> {
self.rowstyles.get_mut(name)
}
pub fn add_colstyle(&mut self, mut style: ColStyle) -> ColStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(&mut self.autonum, "co", &self.colstyles));
}
let sref = style.style_ref();
self.colstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_colstyle(&mut self, name: &str) -> Option<ColStyle> {
self.colstyles.remove(name)
}
pub fn colstyle(&self, name: &str) -> Option<&ColStyle> {
self.colstyles.get(name)
}
pub fn colstyle_mut(&mut self, name: &str) -> Option<&mut ColStyle> {
self.colstyles.get_mut(name)
}
pub fn add_cellstyle(&mut self, mut style: CellStyle) -> CellStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(&mut self.autonum, "ce", &self.cellstyles));
}
let sref = style.style_ref();
self.cellstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_cellstyle(&mut self, name: &str) -> Option<CellStyle> {
self.cellstyles.remove(name)
}
pub fn cellstyle(&self, name: &str) -> Option<&CellStyle> {
self.cellstyles.get(name)
}
pub fn cellstyle_mut(&mut self, name: &str) -> Option<&mut CellStyle> {
self.cellstyles.get_mut(name)
}
pub fn add_paragraphstyle(&mut self, mut style: ParagraphStyle) -> ParagraphStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(
&mut self.autonum,
"para",
&self.paragraphstyles,
));
}
let sref = style.style_ref();
self.paragraphstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_paragraphstyle(&mut self, name: &str) -> Option<ParagraphStyle> {
self.paragraphstyles.remove(name)
}
pub fn paragraphstyle(&self, name: &str) -> Option<&ParagraphStyle> {
self.paragraphstyles.get(name)
}
pub fn paragraphstyle_mut(&mut self, name: &str) -> Option<&mut ParagraphStyle> {
self.paragraphstyles.get_mut(name)
}
pub fn add_textstyle(&mut self, mut style: TextStyle) -> TextStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(&mut self.autonum, "txt", &self.textstyles));
}
let sref = style.style_ref();
self.textstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_textstyle(&mut self, name: &str) -> Option<TextStyle> {
self.textstyles.remove(name)
}
pub fn textstyle(&self, name: &str) -> Option<&TextStyle> {
self.textstyles.get(name)
}
pub fn textstyle_mut(&mut self, name: &str) -> Option<&mut TextStyle> {
self.textstyles.get_mut(name)
}
pub fn add_graphicstyle(&mut self, mut style: GraphicStyle) -> GraphicStyleRef {
if style.name().is_empty() {
style.set_name(auto_style_name(
&mut self.autonum,
"gr",
&self.graphicstyles,
));
}
let sref = style.style_ref();
self.graphicstyles.insert(style.name().to_string(), style);
sref
}
pub fn remove_graphicstyle(&mut self, name: &str) -> Option<GraphicStyle> {
self.graphicstyles.remove(name)
}
pub fn graphicstyle(&self, name: &str) -> Option<&GraphicStyle> {
self.graphicstyles.get(name)
}
pub fn graphicstyle_mut(&mut self, name: &str) -> Option<&mut GraphicStyle> {
self.graphicstyles.get_mut(name)
}
pub fn add_boolean_format(&mut self, mut vstyle: ValueFormatBoolean) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(&mut self.autonum, "val_boolean", &self.formats_boolean).as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_boolean
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_boolean_format(&mut self, name: &str) -> Option<ValueFormatBoolean> {
self.formats_boolean.remove(name)
}
pub fn boolean_format(&self, name: &str) -> Option<&ValueFormatBoolean> {
self.formats_boolean.get(name)
}
pub fn boolean_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatBoolean> {
self.formats_boolean.get_mut(name)
}
pub fn add_number_format(&mut self, mut vstyle: ValueFormatNumber) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(&mut self.autonum, "val_number", &self.formats_number).as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_number
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_number_format(&mut self, name: &str) -> Option<ValueFormatNumber> {
self.formats_number.remove(name)
}
pub fn number_format(&self, name: &str) -> Option<&ValueFormatBoolean> {
self.formats_boolean.get(name)
}
pub fn number_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatBoolean> {
self.formats_boolean.get_mut(name)
}
pub fn add_percentage_format(&mut self, mut vstyle: ValueFormatPercentage) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(
&mut self.autonum,
"val_percentage",
&self.formats_percentage,
)
.as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_percentage
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_percentage_format(&mut self, name: &str) -> Option<ValueFormatPercentage> {
self.formats_percentage.remove(name)
}
pub fn percentage_format(&self, name: &str) -> Option<&ValueFormatPercentage> {
self.formats_percentage.get(name)
}
pub fn percentage_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatPercentage> {
self.formats_percentage.get_mut(name)
}
pub fn add_currency_format(&mut self, mut vstyle: ValueFormatCurrency) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(&mut self.autonum, "val_currency", &self.formats_currency).as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_currency
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_currency_format(&mut self, name: &str) -> Option<ValueFormatCurrency> {
self.formats_currency.remove(name)
}
pub fn currency_format(&self, name: &str) -> Option<&ValueFormatCurrency> {
self.formats_currency.get(name)
}
pub fn currency_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatCurrency> {
self.formats_currency.get_mut(name)
}
pub fn add_text_format(&mut self, mut vstyle: ValueFormatText) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(&mut self.autonum, "val_text", &self.formats_text).as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_text.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_text_format(&mut self, name: &str) -> Option<ValueFormatText> {
self.formats_text.remove(name)
}
pub fn text_format(&self, name: &str) -> Option<&ValueFormatText> {
self.formats_text.get(name)
}
pub fn text_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatText> {
self.formats_text.get_mut(name)
}
pub fn add_datetime_format(&mut self, mut vstyle: ValueFormatDateTime) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(&mut self.autonum, "val_datetime", &self.formats_datetime).as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_datetime
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_datetime_format(&mut self, name: &str) -> Option<ValueFormatDateTime> {
self.formats_datetime.remove(name)
}
pub fn datetime_format(&self, name: &str) -> Option<&ValueFormatDateTime> {
self.formats_datetime.get(name)
}
pub fn datetime_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatDateTime> {
self.formats_datetime.get_mut(name)
}
pub fn add_timeduration_format(
&mut self,
mut vstyle: ValueFormatTimeDuration,
) -> ValueFormatRef {
if vstyle.name().is_empty() {
vstyle.set_name(
auto_style_name(
&mut self.autonum,
"val_timeduration",
&self.formats_timeduration,
)
.as_str(),
);
}
let sref = vstyle.format_ref();
self.formats_timeduration
.insert(vstyle.name().to_string(), vstyle);
sref
}
pub fn remove_timeduration_format(&mut self, name: &str) -> Option<ValueFormatTimeDuration> {
self.formats_timeduration.remove(name)
}
pub fn timeduration_format(&self, name: &str) -> Option<&ValueFormatTimeDuration> {
self.formats_timeduration.get(name)
}
pub fn timeduration_format_mut(&mut self, name: &str) -> Option<&mut ValueFormatTimeDuration> {
self.formats_timeduration.get_mut(name)
}
pub fn add_pagestyle(&mut self, mut pstyle: PageStyle) -> PageStyleRef {
if pstyle.name().is_empty() {
pstyle.set_name(auto_style_name(&mut self.autonum, "page", &self.pagestyles));
}
let sref = pstyle.style_ref();
self.pagestyles.insert(pstyle.name().to_string(), pstyle);
sref
}
pub fn remove_pagestyle(&mut self, name: &str) -> Option<PageStyle> {
self.pagestyles.remove(name)
}
pub fn pagestyle(&self, name: &str) -> Option<&PageStyle> {
self.pagestyles.get(name)
}
pub fn pagestyle_mut(&mut self, name: &str) -> Option<&mut PageStyle> {
self.pagestyles.get_mut(name)
}
pub fn add_masterpage(&mut self, mut mpage: MasterPage) -> MasterPageRef {
if mpage.name().is_empty() {
mpage.set_name(auto_style_name(&mut self.autonum, "mp", &self.masterpages));
}
let sref = mpage.masterpage_ref();
self.masterpages.insert(mpage.name().to_string(), mpage);
sref
}
pub fn remove_masterpage(&mut self, name: &str) -> Option<MasterPage> {
self.masterpages.remove(name)
}
pub fn masterpage(&self, name: &str) -> Option<&MasterPage> {
self.masterpages.get(name)
}
pub fn masterpage_mut(&mut self, name: &str) -> Option<&mut MasterPage> {
self.masterpages.get_mut(name)
}
pub fn add_validation(&mut self, mut valid: Validation) -> ValidationRef {
if valid.name().is_empty() {
valid.set_name(auto_style_name(&mut self.autonum, "val", &self.validations));
}
let vref = valid.validation_ref();
self.validations.insert(valid.name().to_string(), valid);
vref
}
pub fn remove_validation(&mut self, name: &str) -> Option<Validation> {
self.validations.remove(name)
}
pub fn validation(&self, name: &str) -> Option<&Validation> {
self.validations.get(name)
}
pub fn validation_mut(&mut self, name: &str) -> Option<&mut Validation> {
self.validations.get_mut(name)
}
}
#[derive(Clone, Debug)]
pub struct WorkBookConfig {
pub active_table: String,
pub show_grid: bool,
pub show_page_breaks: bool,
pub has_sheet_tabs: bool,
}
impl Default for WorkBookConfig {
fn default() -> Self {
Self {
active_table: "".to_string(),
show_grid: true,
show_page_breaks: false,
has_sheet_tabs: true,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum Visibility {
Visible,
Collapsed,
Filtered,
}
impl Default for Visibility {
fn default() -> Self {
Visibility::Visible
}
}
impl Display for Visibility {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Visibility::Visible => write!(f, "visible"),
Visibility::Collapsed => write!(f, "collapse"),
Visibility::Filtered => write!(f, "filter"),
}
}
}
#[derive(Debug, Clone, Default)]
struct RowHeader {
style: Option<String>,
cellstyle: Option<String>,
visible: Visibility,
repeat: u32,
height: Length,
}
impl RowHeader {
pub(crate) fn new() -> Self {
Self {
style: None,
cellstyle: None,
visible: Default::default(),
repeat: 1,
height: Default::default(),
}
}
pub(crate) fn set_style(&mut self, style: &RowStyleRef) {
self.style = Some(style.to_string());
}
pub(crate) fn clear_style(&mut self) {
self.style = None;
}
pub(crate) fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub(crate) fn set_cellstyle(&mut self, style: &CellStyleRef) {
self.cellstyle = Some(style.to_string());
}
pub(crate) fn clear_cellstyle(&mut self) {
self.cellstyle = None;
}
pub(crate) fn cellstyle(&self) -> Option<&String> {
self.cellstyle.as_ref()
}
pub(crate) fn set_visible(&mut self, visible: Visibility) {
self.visible = visible;
}
pub(crate) fn visible(&self) -> Visibility {
self.visible
}
pub(crate) fn set_repeat(&mut self, repeat: u32) {
assert!(repeat > 0);
self.repeat = repeat;
}
pub(crate) fn repeat(&self) -> u32 {
self.repeat
}
pub(crate) fn set_height(&mut self, height: Length) {
self.height = height;
}
pub(crate) fn height(&self) -> Length {
self.height
}
}
#[derive(Debug, Clone, Default)]
struct ColHeader {
style: Option<String>,
cellstyle: Option<String>,
visible: Visibility,
width: Length,
}
impl ColHeader {
pub(crate) fn new() -> Self {
Self {
style: None,
cellstyle: None,
visible: Default::default(),
width: Default::default(),
}
}
pub(crate) fn set_style(&mut self, style: &ColStyleRef) {
self.style = Some(style.to_string());
}
pub(crate) fn clear_style(&mut self) {
self.style = None;
}
pub(crate) fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub(crate) fn set_cellstyle(&mut self, style: &CellStyleRef) {
self.cellstyle = Some(style.to_string());
}
pub(crate) fn clear_cellstyle(&mut self) {
self.cellstyle = None;
}
pub(crate) fn cellstyle(&self) -> Option<&String> {
self.cellstyle.as_ref()
}
pub(crate) fn set_visible(&mut self, visible: Visibility) {
self.visible = visible;
}
pub(crate) fn visible(&self) -> Visibility {
self.visible
}
pub(crate) fn set_width(&mut self, width: Length) {
self.width = width;
}
pub(crate) fn width(&self) -> Length {
self.width
}
}
#[derive(Clone, Default)]
pub struct Sheet {
name: String,
style: Option<String>,
data: BTreeMap<(u32, u32), CellData>,
col_header: BTreeMap<u32, ColHeader>,
row_header: BTreeMap<u32, RowHeader>,
display: bool,
print: bool,
header_rows: Option<RowRange>,
header_cols: Option<ColRange>,
print_ranges: Option<Vec<CellRange>>,
sheet_config: SheetConfig,
extra: Vec<XmlTag>,
}
impl<'a> IntoIterator for &'a Sheet {
type Item = ((u32, u32), CellContentRef<'a>);
type IntoIter = CellIter<'a>;
fn into_iter(self) -> Self::IntoIter {
CellIter {
it_data: self.data.iter(),
k_data: None,
v_data: None,
}
}
}
#[derive(Clone, Debug)]
pub struct CellIter<'a> {
it_data: std::collections::btree_map::Iter<'a, (u32, u32), CellData>,
k_data: Option<&'a (u32, u32)>,
v_data: Option<&'a CellData>,
}
impl CellIter<'_> {
pub fn peek_cell(&mut self) -> Option<(u32, u32)> {
self.k_data.copied()
}
fn load_next_data(&mut self) {
if let Some((k, v)) = self.it_data.next() {
self.k_data = Some(k);
self.v_data = Some(v);
} else {
self.k_data = None;
self.v_data = None;
}
}
}
impl FusedIterator for CellIter<'_> {}
impl<'a> Iterator for CellIter<'a> {
type Item = ((u32, u32), CellContentRef<'a>);
fn next(&mut self) -> Option<Self::Item> {
if self.k_data.is_none() {
self.load_next_data();
}
if let Some(k_data) = self.k_data {
if let Some(v_data) = self.v_data {
let r = Some((*k_data, v_data.into()));
self.load_next_data();
r
} else {
None
}
} else {
None
}
}
}
#[derive(Clone, Debug)]
pub struct Range<'a> {
range: std::collections::btree_map::Range<'a, (u32, u32), CellData>,
}
impl FusedIterator for Range<'_> {}
impl<'a> Iterator for Range<'a> {
type Item = ((u32, u32), CellContentRef<'a>);
fn next(&mut self) -> Option<Self::Item> {
if let Some((k, v)) = self.range.next() {
Some((*k, v.into()))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl DoubleEndedIterator for Range<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some((k, v)) = self.range.next_back() {
Some((*k, v.into()))
} else {
None
}
}
}
impl ExactSizeIterator for Range<'_> {}
impl fmt::Debug for Sheet {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "name {:?} style {:?}", self.name, self.style)?;
for (k, v) in self.data.iter() {
writeln!(f, " data {:?} {:?}", k, v)?;
}
for (k, v) in &self.col_header {
writeln!(f, "{:?} {:?}", k, v)?;
}
for (k, v) in &self.row_header {
writeln!(f, "{:?} {:?}", k, v)?;
}
if let Some(header_rows) = &self.header_rows {
writeln!(f, "header rows {:?}", header_rows)?;
}
if let Some(header_cols) = &self.header_cols {
writeln!(f, "header cols {:?}", header_cols)?;
}
for xtr in &self.extra {
writeln!(f, "extras {:?}", xtr)?;
}
Ok(())
}
}
impl Sheet {
#[deprecated]
pub fn new_with_name<S: Into<String>>(name: S) -> Self {
Self::new(name)
}
pub fn new<S: Into<String>>(name: S) -> Self {
Sheet {
name: name.into(),
data: BTreeMap::new(),
col_header: Default::default(),
style: None,
header_rows: None,
header_cols: None,
print_ranges: None,
sheet_config: Default::default(),
extra: vec![],
row_header: Default::default(),
display: true,
print: true,
}
}
pub fn clone_no_data(&self) -> Self {
Self {
name: self.name.clone(),
style: self.style.clone(),
data: Default::default(),
col_header: self.col_header.clone(),
row_header: self.row_header.clone(),
display: self.display,
print: self.print,
header_rows: self.header_rows.clone(),
header_cols: self.header_cols.clone(),
print_ranges: self.print_ranges.clone(),
sheet_config: Default::default(),
extra: self.extra.clone(),
}
}
pub fn iter(&self) -> CellIter<'_> {
self.into_iter()
}
pub fn range<R>(&self, range: R) -> Range<'_>
where
R: RangeBounds<(u32, u32)>,
{
Range {
range: self.data.range(range),
}
}
pub fn set_name<V: Into<String>>(&mut self, name: V) {
self.name = name.into();
}
pub fn name(&self) -> &String {
&self.name
}
pub fn config(&self) -> &SheetConfig {
&self.sheet_config
}
pub fn config_mut(&mut self) -> &mut SheetConfig {
&mut self.sheet_config
}
pub fn set_style(&mut self, style: &TableStyleRef) {
self.style = Some(style.to_string());
}
pub fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub fn set_colstyle(&mut self, col: u32, style: &ColStyleRef) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.set_style(style);
}
pub fn clear_colstyle(&mut self, col: u32) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.clear_style();
}
pub fn colstyle(&self, col: u32) -> Option<&String> {
if let Some(col_header) = self.col_header.get(&col) {
col_header.style()
} else {
None
}
}
pub fn set_col_cellstyle(&mut self, col: u32, style: &CellStyleRef) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.set_cellstyle(style);
}
pub fn clear_col_cellstyle(&mut self, col: u32) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.clear_cellstyle();
}
pub fn col_cellstyle(&self, col: u32) -> Option<&String> {
if let Some(col_header) = self.col_header.get(&col) {
col_header.cellstyle()
} else {
None
}
}
pub fn set_col_visible(&mut self, col: u32, visible: Visibility) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.set_visible(visible);
}
pub fn col_visible(&self, col: u32) -> Visibility {
if let Some(col_header) = self.col_header.get(&col) {
col_header.visible()
} else {
Default::default()
}
}
pub fn set_col_width(&mut self, col: u32, width: Length) {
self.col_header
.entry(col)
.or_insert_with(ColHeader::new)
.set_width(width);
}
pub fn col_width(&self, col: u32) -> Length {
if let Some(ch) = self.col_header.get(&col) {
ch.width()
} else {
Length::Default
}
}
pub fn set_rowstyle(&mut self, row: u32, style: &RowStyleRef) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.set_style(style);
}
pub fn clear_rowstyle(&mut self, row: u32) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.clear_style();
}
pub fn rowstyle(&self, row: u32) -> Option<&String> {
if let Some(row_header) = self.row_header.get(&row) {
row_header.style()
} else {
None
}
}
pub fn set_row_cellstyle(&mut self, row: u32, style: &CellStyleRef) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.set_cellstyle(style);
}
pub fn clear_row_cellstyle(&mut self, row: u32) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.clear_cellstyle();
}
pub fn row_cellstyle(&self, row: u32) -> Option<&String> {
if let Some(row_header) = self.row_header.get(&row) {
row_header.cellstyle()
} else {
None
}
}
pub fn set_row_visible(&mut self, row: u32, visible: Visibility) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.set_visible(visible);
}
pub fn row_visible(&self, row: u32) -> Visibility {
if let Some(row_header) = self.row_header.get(&row) {
row_header.visible()
} else {
Default::default()
}
}
pub fn set_row_repeat(&mut self, row: u32, repeat: u32) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.set_repeat(repeat)
}
pub fn row_repeat(&self, row: u32) -> u32 {
if let Some(row_header) = self.row_header.get(&row) {
row_header.repeat()
} else {
Default::default()
}
}
pub fn set_row_height(&mut self, row: u32, height: Length) {
self.row_header
.entry(row)
.or_insert_with(RowHeader::new)
.set_height(height);
}
pub fn row_height(&self, row: u32) -> Length {
if let Some(rh) = self.row_header.get(&row) {
rh.height()
} else {
Length::Default
}
}
pub fn used_cols(&self) -> u32 {
*self.col_header.keys().max().unwrap_or(&0) + 1
}
pub fn used_rows(&self) -> u32 {
*self.row_header.keys().max().unwrap_or(&0) + 1
}
pub fn used_grid_size(&self) -> (u32, u32) {
let max = self.data.keys().fold((0, 0), |mut max, (r, c)| {
max.0 = u32::max(max.0, *r);
max.1 = u32::max(max.1, *c);
max
});
(max.0 + 1, max.1 + 1)
}
pub fn set_display(&mut self, display: bool) {
self.display = display;
}
pub fn display(&self) -> bool {
self.display
}
pub fn set_print(&mut self, print: bool) {
self.print = print;
}
pub fn print(&self) -> bool {
self.print
}
pub fn is_empty(&self, row: u32, col: u32) -> bool {
self.data.get(&(row, col)).is_none()
}
pub fn cell(&self, row: u32, col: u32) -> Option<CellContent> {
let value = self.data.get(&(row, col));
value.map(|value| CellContent {
value: value.value.clone(),
style: value.style.clone(),
formula: value.formula.clone(),
validation_name: value.validation_name.clone(),
span: value.span,
})
}
pub fn add_cell(&mut self, row: u32, col: u32, cell: CellContent) {
self.add_cell_data(
row,
col,
CellData {
value: cell.value,
formula: cell.formula,
style: cell.style,
validation_name: cell.validation_name,
span: cell.span,
},
);
}
pub fn remove_cell(&mut self, row: u32, col: u32) -> Option<CellContent> {
let value = self.data.remove(&(row, col));
if let Some(value) = value {
Some(CellContent {
value: value.value,
style: value.style,
formula: value.formula,
validation_name: value.validation_name,
span: value.span,
})
} else {
None
}
}
pub(crate) fn add_cell_data(&mut self, row: u32, col: u32, cell: CellData) {
self.data.insert((row, col), cell);
}
pub fn set_styled_value<V: Into<Value>>(
&mut self,
row: u32,
col: u32,
value: V,
style: &CellStyleRef,
) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.value = value.into();
cell.style = Some(style.to_string());
}
pub fn set_value<V: Into<Value>>(&mut self, row: u32, col: u32, value: V) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.value = value.into();
}
pub fn value(&self, row: u32, col: u32) -> &Value {
if let Some(cell) = self.data.get(&(row, col)) {
&cell.value
} else {
&Value::Empty
}
}
pub fn set_formula<V: Into<String>>(&mut self, row: u32, col: u32, formula: V) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.formula = Some(formula.into());
}
pub fn clear_formula(&mut self, row: u32, col: u32) {
if let Some(cell) = self.data.get_mut(&(row, col)) {
cell.formula = None;
}
}
pub fn formula(&self, row: u32, col: u32) -> Option<&String> {
if let Some(c) = self.data.get(&(row, col)) {
c.formula.as_ref()
} else {
None
}
}
pub fn set_cellstyle(&mut self, row: u32, col: u32, style: &CellStyleRef) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.style = Some(style.to_string());
}
pub fn clear_cellstyle(&mut self, row: u32, col: u32) {
if let Some(cell) = self.data.get_mut(&(row, col)) {
cell.style = None;
}
}
pub fn cellstyle(&self, row: u32, col: u32) -> Option<&String> {
if let Some(c) = self.data.get(&(row, col)) {
c.style.as_ref()
} else {
None
}
}
pub fn set_validation(&mut self, row: u32, col: u32, validation: &ValidationRef) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.validation_name = Some(validation.to_string());
}
pub fn clear_validation(&mut self, row: u32, col: u32) {
if let Some(cell) = self.data.get_mut(&(row, col)) {
cell.validation_name = None;
}
}
pub fn validation(&self, row: u32, col: u32) -> Option<&String> {
if let Some(c) = self.data.get(&(row, col)) {
c.validation_name.as_ref()
} else {
None
}
}
pub fn set_row_span(&mut self, row: u32, col: u32, span: u32) {
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.span.row_span = span;
}
pub fn row_span(&self, row: u32, col: u32) -> u32 {
if let Some(c) = self.data.get(&(row, col)) {
c.span.row_span
} else {
1
}
}
pub fn set_col_span(&mut self, row: u32, col: u32, span: u32) {
assert!(span > 0);
let mut cell = self.data.entry((row, col)).or_insert_with(CellData::new);
cell.span.col_span = span;
}
pub fn col_span(&self, row: u32, col: u32) -> u32 {
if let Some(c) = self.data.get(&(row, col)) {
c.span.col_span
} else {
1
}
}
pub fn set_header_rows(&mut self, row_start: u32, row_end: u32) {
self.header_rows = Some(RowRange::new(row_start, row_end));
}
pub fn clear_header_rows(&mut self) {
self.header_rows = None;
}
pub fn header_rows(&self) -> &Option<RowRange> {
&self.header_rows
}
pub fn set_header_cols(&mut self, col_start: u32, col_end: u32) {
self.header_cols = Some(ColRange::new(col_start, col_end));
}
pub fn clear_header_cols(&mut self) {
self.header_cols = None;
}
pub fn header_cols(&self) -> &Option<ColRange> {
&self.header_cols
}
pub fn add_print_range(&mut self, range: CellRange) {
self.print_ranges.get_or_insert_with(Vec::new).push(range);
}
pub fn clear_print_ranges(&mut self) {
self.print_ranges = None;
}
pub fn print_ranges(&self) -> Option<&Vec<CellRange>> {
self.print_ranges.as_ref()
}
pub fn split_col_header(&mut self, col: u32) {
self.config_mut().hor_split_mode = SplitMode::Heading;
self.config_mut().hor_split_pos = col + 1;
self.config_mut().position_right = col + 1;
self.config_mut().cursor_x = col + 1;
}
pub fn split_row_header(&mut self, row: u32) {
self.config_mut().vert_split_mode = SplitMode::Heading;
self.config_mut().vert_split_pos = row + 1;
self.config_mut().position_bottom = row + 1;
self.config_mut().cursor_y = row + 1;
}
pub fn split_horizontal(&mut self, col: u32) {
self.config_mut().hor_split_mode = SplitMode::Split;
self.config_mut().hor_split_pos = col;
}
pub fn split_vertical(&mut self, col: u32) {
self.config_mut().vert_split_mode = SplitMode::Split;
self.config_mut().vert_split_pos = col;
}
}
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub enum SplitMode {
None = 0,
Split = 1,
Heading = 2,
}
impl TryFrom<i16> for SplitMode {
type Error = OdsError;
fn try_from(n: i16) -> Result<Self, Self::Error> {
match n {
0 => Ok(SplitMode::None),
1 => Ok(SplitMode::Split),
2 => Ok(SplitMode::Heading),
_ => Err(OdsError::Ods(format!("Invalid split mode {}", n))),
}
}
}
#[derive(Clone, Debug)]
pub struct SheetConfig {
pub cursor_x: u32,
pub cursor_y: u32,
pub hor_split_mode: SplitMode,
pub vert_split_mode: SplitMode,
pub hor_split_pos: u32,
pub vert_split_pos: u32,
pub active_split_range: i16,
pub position_left: u32,
pub position_right: u32,
pub position_top: u32,
pub position_bottom: u32,
pub zoom_type: i16,
pub zoom_value: i32,
pub page_view_zoom_value: i32,
pub show_grid: bool,
}
impl Default for SheetConfig {
fn default() -> Self {
Self {
cursor_x: 0,
cursor_y: 0,
hor_split_mode: SplitMode::None,
vert_split_mode: SplitMode::None,
hor_split_pos: 0,
vert_split_pos: 0,
active_split_range: 2,
position_left: 0,
position_right: 0,
position_top: 0,
position_bottom: 0,
zoom_type: 0,
zoom_value: 100,
page_view_zoom_value: 60,
show_grid: true,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct CellSpan {
row_span: u32,
col_span: u32,
}
impl Default for CellSpan {
fn default() -> Self {
Self::new()
}
}
impl From<CellSpan> for (u32, u32) {
fn from(span: CellSpan) -> Self {
(span.row_span, span.col_span)
}
}
impl From<&CellSpan> for (u32, u32) {
fn from(span: &CellSpan) -> Self {
(span.row_span, span.col_span)
}
}
impl CellSpan {
pub fn new() -> Self {
Self {
row_span: 1,
col_span: 1,
}
}
pub fn set_row_span(&mut self, rows: u32) {
assert!(rows > 0);
self.row_span = rows;
}
pub fn row_span(&self) -> u32 {
self.row_span
}
pub fn set_col_span(&mut self, cols: u32) {
assert!(cols > 0);
self.col_span = cols;
}
pub fn col_span(&self) -> u32 {
self.col_span
}
}
#[derive(Debug, Clone, Default)]
struct CellData {
value: Value,
formula: Option<String>,
style: Option<String>,
validation_name: Option<String>,
span: CellSpan,
}
impl CellData {
pub(crate) fn new() -> Self {
CellData {
value: Value::Empty,
formula: None,
style: None,
validation_name: None,
span: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct CellContentRef<'a> {
pub value: Option<&'a Value>,
pub style: Option<&'a String>,
pub formula: Option<&'a String>,
pub validation_name: Option<&'a String>,
pub span: Option<&'a CellSpan>,
}
impl<'a> From<&'a CellData> for CellContentRef<'a> {
fn from(cd: &'a CellData) -> Self {
CellContentRef {
value: Some(&cd.value),
style: cd.style.as_ref(),
formula: cd.formula.as_ref(),
validation_name: cd.validation_name.as_ref(),
span: Some(&cd.span),
}
}
}
impl<'a> CellContentRef<'a> {
pub fn value(&self) -> &'a Value {
if let Some(value) = self.value {
value
} else {
&Value::Empty
}
}
pub fn formula(&self) -> Option<&'a String> {
self.formula
}
pub fn style(&self) -> Option<&'a String> {
self.style
}
pub fn validation(&self) -> Option<&'a String> {
self.validation_name
}
pub fn row_span(&self) -> u32 {
if let Some(span) = self.span {
span.row_span
} else {
1
}
}
pub fn col_span(&self) -> u32 {
if let Some(span) = self.span {
span.col_span
} else {
1
}
}
}
#[derive(Debug, Clone, Default)]
pub struct CellContent {
pub value: Value,
pub style: Option<String>,
pub formula: Option<String>,
pub validation_name: Option<String>,
pub span: CellSpan,
}
impl CellContent {
pub fn new() -> Self {
Self {
value: Default::default(),
style: None,
formula: None,
validation_name: None,
span: Default::default(),
}
}
pub fn value(&self) -> &Value {
&self.value
}
pub fn set_value<V: Into<Value>>(&mut self, value: V) {
self.value = value.into();
}
pub fn formula(&self) -> Option<&String> {
self.formula.as_ref()
}
pub fn set_formula<V: Into<String>>(&mut self, formula: V) {
self.formula = Some(formula.into());
}
pub fn clear_formula(&mut self) {
self.formula = None;
}
pub fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub fn set_style(&mut self, style: &CellStyleRef) {
self.style = Some(style.to_string());
}
pub fn clear_style(&mut self) {
self.style = None;
}
pub fn validation(&self) -> Option<&String> {
self.validation_name.as_ref()
}
pub fn set_validation(&mut self, validation: &ValidationRef) {
self.validation_name = Some(validation.to_string());
}
pub fn clear_validation(&mut self) {
self.validation_name = None;
}
pub fn set_row_span(&mut self, rows: u32) {
assert!(rows > 0);
self.span.row_span = rows;
}
pub fn row_span(&self) -> u32 {
self.span.row_span
}
pub fn set_col_span(&mut self, cols: u32) {
assert!(cols > 0);
self.span.col_span = cols;
}
pub fn col_span(&self) -> u32 {
self.span.col_span
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum ValueType {
Empty,
Boolean,
Number,
Percentage,
Currency,
Text,
TextXml,
DateTime,
TimeDuration,
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum Value {
Empty,
Boolean(bool),
Number(f64),
Percentage(f64),
Currency(f64, String),
Text(String),
TextXml(Vec<TextTag>),
DateTime(NaiveDateTime),
TimeDuration(Duration),
}
impl Value {
pub fn value_type(&self) -> ValueType {
match self {
Value::Empty => ValueType::Empty,
Value::Boolean(_) => ValueType::Boolean,
Value::Number(_) => ValueType::Number,
Value::Percentage(_) => ValueType::Percentage,
Value::Currency(_, _) => ValueType::Currency,
Value::Text(_) => ValueType::Text,
Value::TextXml(_) => ValueType::TextXml,
Value::TimeDuration(_) => ValueType::TimeDuration,
Value::DateTime(_) => ValueType::DateTime,
}
}
pub fn as_bool_or(&self, d: bool) -> bool {
match self {
Value::Boolean(b) => *b,
_ => d,
}
}
pub fn as_i64_or(&self, d: i64) -> i64 {
match self {
Value::Number(n) => *n as i64,
Value::Percentage(p) => *p as i64,
Value::Currency(v, _) => *v as i64,
_ => d,
}
}
pub fn as_i64_opt(&self) -> Option<i64> {
match self {
Value::Number(n) => Some(*n as i64),
Value::Percentage(p) => Some(*p as i64),
Value::Currency(v, _) => Some(*v as i64),
_ => None,
}
}
pub fn as_u64_or(&self, d: u64) -> u64 {
match self {
Value::Number(n) => *n as u64,
Value::Percentage(p) => *p as u64,
Value::Currency(v, _) => *v as u64,
_ => d,
}
}
pub fn as_u64_opt(&self) -> Option<u64> {
match self {
Value::Number(n) => Some(*n as u64),
Value::Percentage(p) => Some(*p as u64),
Value::Currency(v, _) => Some(*v as u64),
_ => None,
}
}
pub fn as_i32_or(&self, d: i32) -> i32 {
match self {
Value::Number(n) => *n as i32,
Value::Percentage(p) => *p as i32,
Value::Currency(v, _) => *v as i32,
_ => d,
}
}
pub fn as_i32_opt(&self) -> Option<i32> {
match self {
Value::Number(n) => Some(*n as i32),
Value::Percentage(p) => Some(*p as i32),
Value::Currency(v, _) => Some(*v as i32),
_ => None,
}
}
pub fn as_u32_or(&self, d: u32) -> u32 {
match self {
Value::Number(n) => *n as u32,
Value::Percentage(p) => *p as u32,
Value::Currency(v, _) => *v as u32,
_ => d,
}
}
pub fn as_u32_opt(&self) -> Option<u32> {
match self {
Value::Number(n) => Some(*n as u32),
Value::Percentage(p) => Some(*p as u32),
Value::Currency(v, _) => Some(*v as u32),
_ => None,
}
}
pub fn as_i16_or(&self, d: i16) -> i16 {
match self {
Value::Number(n) => *n as i16,
Value::Percentage(p) => *p as i16,
Value::Currency(v, _) => *v as i16,
_ => d,
}
}
pub fn as_i16_opt(&self) -> Option<i16> {
match self {
Value::Number(n) => Some(*n as i16),
Value::Percentage(p) => Some(*p as i16),
Value::Currency(v, _) => Some(*v as i16),
_ => None,
}
}
pub fn as_u16_or(&self, d: u16) -> u16 {
match self {
Value::Number(n) => *n as u16,
Value::Percentage(p) => *p as u16,
Value::Currency(v, _) => *v as u16,
_ => d,
}
}
pub fn as_u16_opt(&self) -> Option<u16> {
match self {
Value::Number(n) => Some(*n as u16),
Value::Percentage(p) => Some(*p as u16),
Value::Currency(v, _) => Some(*v as u16),
_ => None,
}
}
pub fn as_i8_or(&self, d: i8) -> i8 {
match self {
Value::Number(n) => *n as i8,
Value::Percentage(p) => *p as i8,
Value::Currency(v, _) => *v as i8,
_ => d,
}
}
pub fn as_i8_opt(&self) -> Option<i8> {
match self {
Value::Number(n) => Some(*n as i8),
Value::Percentage(p) => Some(*p as i8),
Value::Currency(v, _) => Some(*v as i8),
_ => None,
}
}
pub fn as_u8_or(&self, d: u8) -> u8 {
match self {
Value::Number(n) => *n as u8,
Value::Percentage(p) => *p as u8,
Value::Currency(v, _) => *v as u8,
_ => d,
}
}
pub fn as_u8_opt(&self) -> Option<u8> {
match self {
Value::Number(n) => Some(*n as u8),
Value::Percentage(p) => Some(*p as u8),
Value::Currency(v, _) => Some(*v as u8),
_ => None,
}
}
#[cfg(feature = "use_decimal")]
pub fn as_decimal_or(&self, d: Decimal) -> Decimal {
match self {
Value::Number(n) => Decimal::from_f64(*n).unwrap(),
Value::Currency(v, _) => Decimal::from_f64(*v).unwrap(),
Value::Percentage(p) => Decimal::from_f64(*p).unwrap(),
_ => d,
}
}
#[cfg(feature = "use_decimal")]
pub fn as_decimal_opt(&self) -> Option<Decimal> {
match self {
Value::Number(n) => Some(Decimal::from_f64(*n).unwrap()),
Value::Currency(v, _) => Some(Decimal::from_f64(*v).unwrap()),
Value::Percentage(p) => Some(Decimal::from_f64(*p).unwrap()),
_ => None,
}
}
pub fn as_f64_or(&self, d: f64) -> f64 {
match self {
Value::Number(n) => *n,
Value::Currency(v, _) => *v,
Value::Percentage(p) => *p,
_ => d,
}
}
pub fn as_f64_opt(&self) -> Option<f64> {
match self {
Value::Number(n) => Some(*n),
Value::Currency(v, _) => Some(*v),
Value::Percentage(p) => Some(*p),
_ => None,
}
}
pub fn as_str_or<'a>(&'a self, d: &'a str) -> &'a str {
match self {
Value::Text(s) => s.as_ref(),
_ => d,
}
}
pub fn as_cow_str_or<'a>(&'a self, d: &'a str) -> Cow<'a, str> {
match self {
Value::Text(s) => Cow::from(s),
Value::TextXml(v) => {
let mut buf = String::new();
for t in v {
if !buf.is_empty() {
buf.push('\n');
}
t.extract_text(&mut buf);
}
Cow::from(buf)
}
_ => Cow::from(d),
}
}
pub fn as_str_opt(&self) -> Option<&str> {
match self {
Value::Text(s) => Some(s.as_ref()),
_ => None,
}
}
pub fn as_timeduration_or(&self, d: Duration) -> Duration {
match self {
Value::TimeDuration(td) => *td,
_ => d,
}
}
pub fn as_timeduration_opt(&self) -> Option<Duration> {
match self {
Value::TimeDuration(td) => Some(*td),
_ => None,
}
}
pub fn as_datetime_or(&self, d: NaiveDateTime) -> NaiveDateTime {
match self {
Value::DateTime(dt) => *dt,
_ => d,
}
}
pub fn as_datetime_opt(&self) -> Option<NaiveDateTime> {
match self {
Value::DateTime(dt) => Some(*dt),
_ => None,
}
}
pub fn as_date_or(&self, d: NaiveDate) -> NaiveDate {
match self {
Value::DateTime(dt) => dt.date(),
_ => d,
}
}
pub fn as_date_opt(&self) -> Option<NaiveDate> {
match self {
Value::DateTime(dt) => Some(dt.date()),
_ => None,
}
}
pub fn currency(&self) -> &str {
match self {
Value::Currency(_, c) => c,
_ => "",
}
}
#[allow(clippy::needless_range_loop)]
pub fn new_currency<S: AsRef<str>>(cur: S, value: f64) -> Self {
Value::Currency(value, cur.as_ref().to_string())
}
pub fn new_percentage(value: f64) -> Self {
Value::Percentage(value)
}
}
impl Default for Value {
fn default() -> Self {
Value::Empty
}
}
#[macro_export]
macro_rules! currency {
($c:expr, $v:expr) => {
Value::new_currency($c, $v as f64)
};
}
#[macro_export]
macro_rules! percent {
($v:expr) => {
Value::new_percentage($v)
};
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Empty
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::Text(s.to_string())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::Text(s)
}
}
impl From<&String> for Value {
fn from(s: &String) -> Self {
Value::Text(s.to_string())
}
}
impl From<TextTag> for Value {
fn from(t: TextTag) -> Self {
Value::TextXml(vec![t])
}
}
impl From<Vec<TextTag>> for Value {
fn from(t: Vec<TextTag>) -> Self {
Value::TextXml(t)
}
}
impl From<Option<&str>> for Value {
fn from(s: Option<&str>) -> Self {
if let Some(s) = s {
Value::Text(s.to_string())
} else {
Value::Empty
}
}
}
impl From<Option<&String>> for Value {
fn from(s: Option<&String>) -> Self {
if let Some(s) = s {
Value::Text(s.to_string())
} else {
Value::Empty
}
}
}
impl From<Option<String>> for Value {
fn from(s: Option<String>) -> Self {
if let Some(s) = s {
Value::Text(s)
} else {
Value::Empty
}
}
}
#[cfg(feature = "use_decimal")]
impl From<Decimal> for Value {
fn from(f: Decimal) -> Self {
Value::Number(f.to_f64().unwrap())
}
}
#[cfg(feature = "use_decimal")]
impl From<Option<Decimal>> for Value {
fn from(f: Option<Decimal>) -> Self {
if let Some(f) = f {
Value::Number(f.to_f64().unwrap())
} else {
Value::Empty
}
}
}
macro_rules! from_number {
($l:ty) => {
impl From<$l> for Value {
#![allow(trivial_numeric_casts)]
fn from(f: $l) -> Self {
Value::Number(f as f64)
}
}
impl From<&$l> for Value {
#![allow(trivial_numeric_casts)]
fn from(f: &$l) -> Self {
Value::Number(*f as f64)
}
}
impl From<Option<$l>> for Value {
#![allow(trivial_numeric_casts)]
fn from(f: Option<$l>) -> Self {
if let Some(f) = f {
Value::Number(f as f64)
} else {
Value::Empty
}
}
}
impl From<Option<&$l>> for Value {
#![allow(trivial_numeric_casts)]
fn from(f: Option<&$l>) -> Self {
if let Some(f) = f {
Value::Number(*f as f64)
} else {
Value::Empty
}
}
}
};
}
from_number!(f64);
from_number!(f32);
from_number!(i64);
from_number!(i32);
from_number!(i16);
from_number!(i8);
from_number!(u64);
from_number!(u32);
from_number!(u16);
from_number!(u8);
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Boolean(b)
}
}
impl From<Option<bool>> for Value {
fn from(b: Option<bool>) -> Self {
if let Some(b) = b {
Value::Boolean(b)
} else {
Value::Empty
}
}
}
impl From<NaiveDateTime> for Value {
fn from(dt: NaiveDateTime) -> Self {
Value::DateTime(dt)
}
}
impl From<Option<NaiveDateTime>> for Value {
fn from(dt: Option<NaiveDateTime>) -> Self {
if let Some(dt) = dt {
Value::DateTime(dt)
} else {
Value::Empty
}
}
}
impl From<NaiveDate> for Value {
fn from(dt: NaiveDate) -> Self {
Value::DateTime(dt.and_hms_opt(0, 0, 0).unwrap())
}
}
impl From<Option<NaiveDate>> for Value {
fn from(dt: Option<NaiveDate>) -> Self {
if let Some(dt) = dt {
Value::DateTime(dt.and_hms_opt(0, 0, 0).unwrap())
} else {
Value::Empty
}
}
}
impl From<NaiveTime> for Value {
fn from(ti: NaiveTime) -> Self {
Value::DateTime(NaiveDateTime::new(
NaiveDate::from_ymd_opt(1900, 1, 1).unwrap(),
ti,
))
}
}
impl From<Option<NaiveTime>> for Value {
fn from(dt: Option<NaiveTime>) -> Self {
if let Some(ti) = dt {
Value::DateTime(NaiveDateTime::new(
NaiveDate::from_ymd_opt(1900, 1, 1).unwrap(),
ti,
))
} else {
Value::Empty
}
}
}
impl From<Duration> for Value {
fn from(d: Duration) -> Self {
Value::TimeDuration(d)
}
}
impl From<Option<Duration>> for Value {
fn from(d: Option<Duration>) -> Self {
if let Some(d) = d {
Value::TimeDuration(d)
} else {
Value::Empty
}
}
}