#![doc(html_root_url = "https://docs.rs/spreadsheet-ods/0.4.0")]
use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::path::PathBuf;
use chrono::{NaiveDate, NaiveDateTime};
#[cfg(feature = "use_decimal")]
use rust_decimal::prelude::*;
#[cfg(feature = "use_decimal")]
use rust_decimal::Decimal;
use time::Duration;
pub use error::OdsError;
pub use format::ValueFormat;
pub use io::{read_ods, write_ods};
pub use refs::{CellRange, CellRef, ColRange, RowRange};
pub use style::{Angle, Length, Style};
use crate::attrmap::{AttrTableCol, AttrTableRow};
use crate::style::{FontFaceDecl, PageLayout};
use crate::text::TextTag;
use crate::xmltree::XmlTag;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
mod attrmap;
pub mod defaultstyles;
pub mod error;
pub mod format;
pub mod formula;
mod io;
pub mod refs;
pub mod style;
pub mod text;
pub mod xmltree;
pub(crate) mod sealed {
pub trait Sealed {}
}
#[allow(non_camel_case_types)]
pub type ucell = u32;
#[derive(Clone, Default)]
pub struct WorkBook {
sheets: Vec<Sheet>,
fonts: HashMap<String, FontFaceDecl>,
styles: HashMap<String, Style>,
formats: HashMap<String, ValueFormat>,
def_styles: HashMap<ValueType, String>,
page_layouts: HashMap<String, PageLayout>,
file: Option<PathBuf>,
extra: Vec<XmlTag>,
}
impl fmt::Debug for WorkBook {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for s in self.sheets.iter() {
writeln!(f, "{:?}", s)?;
}
for s in self.fonts.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.styles.values() {
writeln!(f, "{:?}", s)?;
}
for s in self.formats.values() {
writeln!(f, "{:?}", s)?;
}
for (t, s) in &self.def_styles {
writeln!(f, "{:?} -> {:?}", t, s)?;
}
for s in self.page_layouts.values() {
writeln!(f, "{:?}", s)?;
}
for xtr in &self.extra {
writeln!(f, "extras {:?}", xtr)?;
}
writeln!(f, "{:?}", self.file)?;
Ok(())
}
}
impl WorkBook {
pub fn new() -> Self {
WorkBook {
sheets: Default::default(),
fonts: Default::default(),
styles: Default::default(),
formats: Default::default(),
def_styles: Default::default(),
page_layouts: Default::default(),
file: None,
extra: vec![],
}
}
pub fn num_sheets(&self) -> usize {
self.sheets.len()
}
pub fn sheet(&self, n: usize) -> &Sheet {
&self.sheets[n]
}
pub fn sheet_mut(&mut self, n: usize) -> &mut Sheet {
&mut self.sheets[n]
}
pub fn insert_sheet(&mut self, i: usize, sheet: Sheet) {
self.sheets.insert(i, sheet);
}
pub fn push_sheet(&mut self, sheet: Sheet) {
self.sheets.push(sheet);
}
pub fn remove_sheet(&mut self, n: usize) -> Sheet {
self.sheets.remove(n)
}
pub fn add_def_style(&mut self, value_type: ValueType, style: &str) {
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 find_value_format(&self, style_name: &str) -> Option<&ValueFormat> {
if let Some(style) = self.styles.get(style_name) {
if let Some(value_format_name) = style.value_format() {
if let Some(value_format) = self.formats.get(value_format_name) {
return Some(&value_format);
}
}
}
None
}
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_style(&mut self, style: Style) {
self.styles.insert(style.name().to_string(), style);
}
pub fn remove_style(&mut self, name: &str) -> Option<Style> {
self.styles.remove(name)
}
pub fn style(&self, name: &str) -> Option<&Style> {
self.styles.get(name)
}
pub fn style_mut(&mut self, name: &str) -> Option<&mut Style> {
self.styles.get_mut(name)
}
pub fn add_format(&mut self, vstyle: ValueFormat) {
self.formats.insert(vstyle.name().to_string(), vstyle);
}
pub fn remove_format(&mut self, name: &str) -> Option<ValueFormat> {
self.formats.remove(name)
}
pub fn format(&self, name: &str) -> Option<&ValueFormat> {
self.formats.get(name)
}
pub fn format_mut(&mut self, name: &str) -> Option<&mut ValueFormat> {
self.formats.get_mut(name)
}
pub fn add_pagelayout(&mut self, pagelayout: PageLayout) {
self.page_layouts
.insert(pagelayout.name().to_string(), pagelayout);
}
pub fn remove_pagelayout(&mut self, name: &str) -> Option<PageLayout> {
self.page_layouts.remove(name)
}
pub fn pagelayout(&self, name: &str) -> Option<&PageLayout> {
self.page_layouts.get(name)
}
pub fn pagelayout_mut(&mut self, name: &str) -> Option<&mut PageLayout> {
self.page_layouts.get_mut(name)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Visibility {
Visible,
Collapsed,
Filtered,
}
impl FromStr for Visibility {
type Err = OdsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"visible" => Ok(Visibility::Visible),
"filter" => Ok(Visibility::Filtered),
"collapse" => Ok(Visibility::Collapsed),
_ => Err(OdsError::Ods(format!(
"Unknown value for table:visibility {}",
s
))),
}
}
}
impl Default for Visibility {
fn default() -> Self {
Visibility::Visible
}
}
impl Display for Visibility {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Visibility::Visible => write!(f, "visible"),
Visibility::Collapsed => write!(f, "collapse"),
Visibility::Filtered => write!(f, "filter"),
}
}
}
#[derive(Debug, Clone, Default)]
struct RowColHeader {
style: Option<String>,
cell_style: Option<String>,
visible: Visibility,
}
impl RowColHeader {
pub fn new() -> Self {
Self {
style: None,
cell_style: None,
visible: Default::default(),
}
}
pub fn set_style<S: Into<String>>(&mut self, style: S) {
self.style = Some(style.into());
}
pub fn clear_style(&mut self) {
self.style = None;
}
pub fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub fn set_cell_style<S: Into<String>>(&mut self, style: S) {
self.cell_style = Some(style.into());
}
pub fn clear_cell_style(&mut self) {
self.cell_style = None;
}
pub fn cell_style(&self) -> Option<&String> {
self.cell_style.as_ref()
}
pub fn set_visible(&mut self, visible: Visibility) {
self.visible = visible;
}
pub fn visible(&self) -> Visibility {
self.visible
}
}
#[derive(Clone, Default)]
pub struct Sheet {
name: String,
style: Option<String>,
data: BTreeMap<(ucell, ucell), SCell>,
col_header: BTreeMap<ucell, RowColHeader>,
row_header: BTreeMap<ucell, RowColHeader>,
display: bool,
print: bool,
header_rows: Option<RowRange>,
header_cols: Option<ColRange>,
print_ranges: Option<Vec<CellRange>>,
extra: Vec<XmlTag>,
}
impl fmt::Debug for Sheet {
fn fmt(&self, f: &mut fmt::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 {
pub fn new() -> Self {
Sheet {
name: String::from(""),
data: BTreeMap::new(),
col_header: Default::default(),
style: None,
header_rows: None,
header_cols: None,
print_ranges: None,
extra: vec![],
row_header: Default::default(),
display: true,
print: true,
}
}
pub fn new_with_name<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,
extra: vec![],
row_header: Default::default(),
display: true,
print: true,
}
}
pub fn set_name<V: Into<String>>(&mut self, name: V) {
self.name = name.into();
}
pub fn name(&self) -> &String {
&self.name
}
pub fn set_style<V: Into<String>>(&mut self, style: V) {
self.style = Some(style.into());
}
pub fn style(&self) -> Option<&String> {
self.style.as_ref()
}
pub fn set_column_style<V: Into<String>>(&mut self, col: ucell, style: V) {
self.col_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_style(style);
}
pub fn clear_column_style(&mut self, col: ucell) {
self.col_header
.entry(col)
.or_insert_with(RowColHeader::new)
.clear_style();
}
pub fn column_style(&self, col: ucell) -> Option<&String> {
if let Some(col_header) = self.col_header.get(&col) {
col_header.style()
} else {
None
}
}
pub fn set_column_cell_style<V: Into<String>>(&mut self, col: ucell, style: V) {
self.col_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_cell_style(style);
}
pub fn clear_column_cell_style(&mut self, col: ucell) {
self.col_header
.entry(col)
.or_insert_with(RowColHeader::new)
.clear_cell_style();
}
pub fn column_cell_style(&self, col: ucell) -> Option<&String> {
if let Some(col_header) = self.col_header.get(&col) {
col_header.cell_style()
} else {
None
}
}
pub fn set_column_visible(&mut self, col: ucell, visible: Visibility) {
self.col_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_visible(visible);
}
pub fn column_visible(&self, col: ucell) -> Visibility {
if let Some(col_header) = self.col_header.get(&col) {
col_header.visible()
} else {
Default::default()
}
}
pub fn set_col_width(&mut self, workbook: &mut WorkBook, col: ucell, width: Length) {
let style_name = format!("co{}", col);
let mut col_style = if let Some(style) = workbook.remove_style(&style_name) {
style
} else {
Style::new_col_style(&style_name, "")
};
col_style.col_mut().set_col_width(width);
col_style.col_mut().set_use_optimal_col_width(false);
workbook.add_style(col_style);
self.set_column_style(col, &style_name);
}
pub fn set_row_style<V: Into<String>>(&mut self, col: ucell, style: V) {
self.row_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_style(style);
}
pub fn clear_row_style(&mut self, col: ucell) {
self.row_header
.entry(col)
.or_insert_with(RowColHeader::new)
.clear_style();
}
pub fn row_style(&self, col: ucell) -> Option<&String> {
if let Some(row_header) = self.row_header.get(&col) {
row_header.style()
} else {
None
}
}
pub fn set_row_cell_style<V: Into<String>>(&mut self, col: ucell, style: V) {
self.row_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_cell_style(style);
}
pub fn clear_row_cell_style(&mut self, col: ucell) {
self.row_header
.entry(col)
.or_insert_with(RowColHeader::new)
.clear_cell_style();
}
pub fn row_cell_style(&self, col: ucell) -> Option<&String> {
if let Some(row_header) = self.row_header.get(&col) {
row_header.cell_style()
} else {
None
}
}
pub fn set_row_visible(&mut self, col: ucell, visible: Visibility) {
self.row_header
.entry(col)
.or_insert_with(RowColHeader::new)
.set_visible(visible);
}
pub fn row_visible(&self, col: ucell) -> Visibility {
if let Some(row_header) = self.row_header.get(&col) {
row_header.visible()
} else {
Default::default()
}
}
pub fn set_row_height(&mut self, workbook: &mut WorkBook, row: ucell, height: Length) {
let style_name = format!("ro{}", row);
let mut row_style = if let Some(style) = workbook.remove_style(&style_name) {
style
} else {
Style::new_row_style(&style_name, "")
};
row_style.row_mut().set_row_height(height);
row_style.row_mut().set_use_optimal_row_height(false);
workbook.add_style(row_style);
self.set_row_style(row, &style_name);
}
pub fn used_grid_size(&self) -> (ucell, ucell) {
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: ucell, col: ucell) -> bool {
self.data.get(&(row, col)).is_none()
}
pub fn cell(&self, row: ucell, col: ucell) -> Option<&SCell> {
self.data.get(&(row, col))
}
pub fn cell_mut(&mut self, row: ucell, col: ucell) -> &mut SCell {
self.data.entry((row, col)).or_insert_with(SCell::new)
}
pub fn add_cell(&mut self, row: ucell, col: ucell, cell: SCell) -> Option<SCell> {
self.data.insert((row, col), cell)
}
pub fn remove_cell(&mut self, row: ucell, col: ucell) -> Option<SCell> {
self.data.remove(&(row, col))
}
pub fn set_styled_value<V: Into<Value>, W: Into<String>>(
&mut self,
row: ucell,
col: ucell,
value: V,
style: W,
) {
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.value = value.into();
cell.style = Some(style.into());
}
pub fn set_value<V: Into<Value>>(&mut self, row: ucell, col: ucell, value: V) {
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.value = value.into();
}
pub fn value(&self, row: ucell, col: ucell) -> &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: ucell, col: ucell, formula: V) {
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.formula = Some(formula.into());
}
pub fn formula(&self, row: ucell, col: ucell) -> Option<&String> {
if let Some(c) = self.data.get(&(row, col)) {
c.formula.as_ref()
} else {
None
}
}
pub fn set_cell_style<V: Into<String>>(&mut self, row: ucell, col: ucell, style: V) {
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.style = Some(style.into());
}
pub fn cell_style(&self, row: ucell, col: ucell) -> Option<&String> {
if let Some(c) = self.data.get(&(row, col)) {
c.style.as_ref()
} else {
None
}
}
pub fn set_row_span(&mut self, row: ucell, col: ucell, span: ucell) {
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.span.0 = span;
}
pub fn row_span(&self, row: ucell, col: ucell) -> ucell {
if let Some(c) = self.data.get(&(row, col)) {
c.span.0
} else {
1
}
}
pub fn set_col_span(&mut self, row: ucell, col: ucell, span: ucell) {
assert!(span > 0);
let mut cell = self.data.entry((row, col)).or_insert_with(SCell::new);
cell.span.1 = span;
}
pub fn col_span(&self, row: ucell, col: ucell) -> ucell {
if let Some(c) = self.data.get(&(row, col)) {
c.span.1
} else {
1
}
}
pub fn set_header_rows(&mut self, row_start: ucell, row_end: ucell) {
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: ucell, col_end: ucell) {
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()
}
}
#[derive(Debug, Clone, Default)]
pub struct SCell {
value: Value,
formula: Option<String>,
style: Option<String>,
span: (ucell, ucell),
}
impl SCell {
pub fn new() -> Self {
SCell {
value: Value::Empty,
formula: None,
style: None,
span: (1, 1),
}
}
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 style(&self) -> Option<&String> {
self.style.as_ref()
}
pub fn set_style<V: Into<String>>(&mut self, style: V) {
self.style = Some(style.into());
}
pub fn set_row_span(&mut self, rows: ucell) {
assert!(rows > 0);
self.span.0 = rows;
}
pub fn row_span(&self) -> ucell {
self.span.0
}
pub fn set_col_span(&mut self, cols: ucell) {
assert!(cols > 0);
self.span.1 = cols;
}
pub fn col_span(&self) -> ucell {
self.span.1
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValueType {
Empty,
Boolean,
Number,
Percentage,
Currency,
Text,
TextXml,
DateTime,
TimeDuration,
}
impl Default for ValueType {
fn default() -> Self {
ValueType::Text
}
}
#[derive(Debug, Clone)]
pub enum Value {
Empty,
Boolean(bool),
Number(f64),
Percentage(f64),
Currency(String, f64),
Text(String),
TextXml(Box<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_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,
}
}
#[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_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,
}
}
}
impl Default for Value {
fn default() -> Self {
Value::Empty
}
}
#[macro_export]
macro_rules! currency {
($c:expr, $v:expr) => {
Value::Currency($c.to_string(), $v as f64)
};
}
#[macro_export]
macro_rules! percent {
($v:expr) => {
Value::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(Box::new(t))
}
}
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())
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value::Number(f)
}
}
impl From<f32> for Value {
fn from(f: f32) -> Self {
Value::Number(f as f64)
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value::Number(i as f64)
}
}
impl From<i32> for Value {
fn from(i: i32) -> Self {
Value::Number(i as f64)
}
}
impl From<i16> for Value {
fn from(i: i16) -> Self {
Value::Number(i as f64)
}
}
impl From<i8> for Value {
fn from(i: i8) -> Self {
Value::Number(i as f64)
}
}
impl From<u64> for Value {
fn from(u: u64) -> Self {
Value::Number(u as f64)
}
}
impl From<u32> for Value {
fn from(u: u32) -> Self {
Value::Number(u as f64)
}
}
impl From<u16> for Value {
fn from(u: u16) -> Self {
Value::Number(u as f64)
}
}
impl From<u8> for Value {
fn from(u: u8) -> Self {
Value::Number(u as f64)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Boolean(b)
}
}
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(0, 0, 0))
}
}
impl From<Option<NaiveDate>> for Value {
fn from(dt: Option<NaiveDate>) -> Self {
if let Some(dt) = dt {
Value::DateTime(dt.and_hms(0, 0, 0))
} 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
}
}
}