Skip to content

Commit

Permalink
Playtime: Improve Lua serialization of matrix sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Dec 11, 2023
1 parent 70caaef commit 5e93ce0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 11 deletions.
25 changes: 23 additions & 2 deletions main/src/infrastructure/ui/lua_serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
type Ok = ();
type Error = Error;
type SerializeSeq = Self;
type SerializeTuple = Impossible<(), Error>;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Impossible<(), Error>;
type SerializeMap = Self;
Expand Down Expand Up @@ -204,7 +204,8 @@ impl<'a> ser::Serializer for &'a mut Serializer {
}

fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
Err(Error::Unsupported("tuple"))
self.output += "{";
Ok(self)
}

fn serialize_tuple_struct(
Expand Down Expand Up @@ -282,6 +283,26 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer {
}
}

impl<'a> ser::SerializeTuple for &'a mut Serializer {
type Ok = ();
type Error = Error;

fn serialize_element<T: ?Sized>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: Serialize,
{
if !self.output.ends_with('{') {
self.output += ", ";
}
value.serialize(&mut **self)
}

fn end(self) -> Result<()> {
self.output += "}";
Ok(())
}
}

impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
type Ok = ();
type Error = Error;
Expand Down
40 changes: 31 additions & 9 deletions playtime-api/src/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use base64::engine::general_purpose::URL_SAFE_NO_PAD as BASE64_ENGINE;
use base64::Engine;
use chrono::{Local, NaiveDateTime, Utc};
use serde::ser::SerializeSeq;
use serde::ser::{SerializeSeq, SerializeTuple};
use serde::{Deserialize, Serialize, Serializer};
use serde_tuple::{Deserialize_tuple, Serialize_tuple};
use std::cmp;
Expand Down Expand Up @@ -105,6 +105,28 @@ pub struct MatrixSequenceEvent {
pub message: MatrixSequenceMessage,
}

/// A very compact representation of an event.
///
/// The compactness is achieved using tuple serialization.
///
/// Pro:
///
/// - If used with a CSV serializer, the outcome can be made look as "noise-less" as
/// REAPER's MIDI sequence format (newline to separate events, space delimiter, unquoted strings).
/// - If used with JSON/Lua serializer, the outcome is valid JSON/Lua while still being compact.
/// No need for string embedding (which looks especially bad in JSON due to newline escaping).
/// - If used with a binary serializer (e.g. bincode or msgpack), one can achieve a *really* compact
/// serialization that also tops REAPER's MIDI sequence format. That will come in handy with
/// large undo histories or storage within RPP (in RPPs, we are base64-encoded, so the
/// human-readable-text advantage is not present anyway).
/// - TODO-high-ms3 Especially the last point could be desirable for MIDI sequences as well.
/// Use serde for them, too!
///
/// Contra:
///
/// - Not self-describing. However: If embedded in some `Serialize` wrapper that evaluates
/// `is_human_readable`, one could switch between this non-descriptive serialization style and a
/// (derived) descriptive serialization style. So we can have both if we want.
impl Serialize for MatrixSequenceEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand All @@ -114,7 +136,7 @@ impl Serialize for MatrixSequenceEvent {
use MatrixSequenceMessage::*;
match self.message {
PanicMatrix => {
let mut seq = serializer.serialize_seq(Some(2))?;
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&self.pulse_diff)?;
if hr {
seq.serialize_element(&"pm")?;
Expand All @@ -124,42 +146,42 @@ impl Serialize for MatrixSequenceEvent {
seq.end()
}
StopMatrix => {
let mut seq = serializer.serialize_seq(Some(2))?;
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&1u8)?;
seq.end()
}
PanicColumn(m) => {
let mut seq = serializer.serialize_seq(Some(3))?;
let mut seq = serializer.serialize_tuple(3)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&2u8)?;
seq.serialize_element(&m.index)?;
seq.end()
}
StopColumn(m) => {
let mut seq = serializer.serialize_seq(Some(3))?;
let mut seq = serializer.serialize_tuple(3)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&3u8)?;
seq.serialize_element(&m.index)?;
seq.end()
}
StartScene(m) => {
let mut seq = serializer.serialize_seq(Some(3))?;
let mut seq = serializer.serialize_tuple(3)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&4u8)?;
seq.serialize_element(&m.index)?;
seq.end()
}
PanicSlot(m) => {
let mut seq = serializer.serialize_seq(Some(4))?;
let mut seq = serializer.serialize_tuple(4)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&5u8)?;
seq.serialize_element(&m.column_index)?;
seq.serialize_element(&m.row_index)?;
seq.end()
}
StartSlot(m) => {
let mut seq = serializer.serialize_seq(Some(4))?;
let mut seq = serializer.serialize_tuple(4)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&6u8)?;
seq.serialize_element(&m.column_index)?;
Expand All @@ -168,7 +190,7 @@ impl Serialize for MatrixSequenceEvent {
}

StopSlot(m) => {
let mut seq = serializer.serialize_seq(Some(4))?;
let mut seq = serializer.serialize_tuple(4)?;
seq.serialize_element(&self.pulse_diff)?;
seq.serialize_element(&7u8)?;
seq.serialize_element(&m.column_index)?;
Expand Down

0 comments on commit 5e93ce0

Please sign in to comment.