tellers-timeline-core 0.1.0

An OpenTimelineIO timeline engine with policy-driven editing, sync, sanitization, and effect conventions.
Documentation
use serde::Serialize;
use serde_json::ser::{CompactFormatter, PrettyFormatter, Serializer};
use serde_json::Result as SerdeResult;
use std::io;

fn round_to_precision(value: f64, precision: usize) -> f64 {
    if !value.is_finite() {
        return value;
    }
    let factor = 10f64.powi(precision as i32);
    (value * factor).round() / factor
}

struct PrecisionFormatter<F: serde_json::ser::Formatter> {
    inner: F,
    precision: Option<usize>,
}

impl<F: serde_json::ser::Formatter> PrecisionFormatter<F> {
    fn new(inner: F, precision: Option<usize>) -> Self {
        Self { inner, precision }
    }
}

impl<F: serde_json::ser::Formatter> serde_json::ser::Formatter for PrecisionFormatter<F> {
    fn write_null<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.write_null(writer)
    }
    fn write_bool<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: bool) -> io::Result<()> {
        self.inner.write_bool(writer, value)
    }
    fn write_i8<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: i8) -> io::Result<()> {
        self.inner.write_i8(writer, value)
    }
    fn write_i16<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: i16) -> io::Result<()> {
        self.inner.write_i16(writer, value)
    }
    fn write_i32<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: i32) -> io::Result<()> {
        self.inner.write_i32(writer, value)
    }
    fn write_i64<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: i64) -> io::Result<()> {
        self.inner.write_i64(writer, value)
    }
    fn write_u8<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: u8) -> io::Result<()> {
        self.inner.write_u8(writer, value)
    }
    fn write_u16<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: u16) -> io::Result<()> {
        self.inner.write_u16(writer, value)
    }
    fn write_u32<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: u32) -> io::Result<()> {
        self.inner.write_u32(writer, value)
    }
    fn write_u64<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: u64) -> io::Result<()> {
        self.inner.write_u64(writer, value)
    }
    fn write_f32<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: f32) -> io::Result<()> {
        match self.precision {
            Some(p) => self
                .inner
                .write_f32(writer, round_to_precision(value as f64, p) as f32),
            None => self.inner.write_f32(writer, value),
        }
    }
    fn write_f64<W: ?Sized + io::Write>(&mut self, writer: &mut W, value: f64) -> io::Result<()> {
        match self.precision {
            Some(p) => self.inner.write_f64(writer, round_to_precision(value, p)),
            None => self.inner.write_f64(writer, value),
        }
    }
    fn begin_string<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.begin_string(writer)
    }
    fn end_string<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_string(writer)
    }
    fn write_string_fragment<W: ?Sized + io::Write>(
        &mut self,
        writer: &mut W,
        fragment: &str,
    ) -> io::Result<()> {
        self.inner.write_string_fragment(writer, fragment)
    }
    fn write_char_escape<W: ?Sized + io::Write>(
        &mut self,
        writer: &mut W,
        char_escape: serde_json::ser::CharEscape,
    ) -> io::Result<()> {
        self.inner.write_char_escape(writer, char_escape)
    }
    fn begin_array<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.begin_array(writer)
    }
    fn end_array<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_array(writer)
    }
    fn begin_array_value<W: ?Sized + io::Write>(
        &mut self,
        writer: &mut W,
        first: bool,
    ) -> io::Result<()> {
        self.inner.begin_array_value(writer, first)
    }
    fn end_array_value<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_array_value(writer)
    }
    fn begin_object<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.begin_object(writer)
    }
    fn end_object<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_object(writer)
    }
    fn begin_object_key<W: ?Sized + io::Write>(
        &mut self,
        writer: &mut W,
        first: bool,
    ) -> io::Result<()> {
        self.inner.begin_object_key(writer, first)
    }
    fn end_object_key<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_object_key(writer)
    }
    fn begin_object_value<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.begin_object_value(writer)
    }
    fn end_object_value<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
        self.inner.end_object_value(writer)
    }
}

pub fn to_json_with_precision<T: Serialize>(
    value: &T,
    precision: Option<usize>,
    pretty: bool,
) -> SerdeResult<String> {
    let mut out = Vec::new();
    if pretty {
        let fmt = PrecisionFormatter::new(PrettyFormatter::with_indent(b"  "), precision);
        let mut ser = Serializer::with_formatter(&mut out, fmt);
        value.serialize(&mut ser)?;
    } else {
        let fmt = PrecisionFormatter::new(CompactFormatter, precision);
        let mut ser = Serializer::with_formatter(&mut out, fmt);
        value.serialize(&mut ser)?;
    }
    Ok(String::from_utf8(out).expect("valid utf8"))
}