rs-bag 0.1.2

Read, write and modify ROS 2 rosbag2 sqlite3 (.db3) storage files
use serde::{Deserialize, Serialize};
use turso::Row;

use crate::Error;
use crate::error::Result;

#[derive(Debug, Serialize, Deserialize)]
pub struct RawMessage {
    pub id: i64,
    pub topic_id: i64,
    pub timestamp: i64,
    pub serialization_format: String,
    pub data: Vec<u8>,
}

impl RawMessage {
    fn fields_from_row(row: Row) -> Result<(i64, i64, i64, Vec<u8>)> {
        let id = row
            .get_value(0)?
            .as_integer()
            .copied()
            .ok_or(Error::row_conversion("id", "an integer"))?;

        let timestamp = row
            .get_value(1)?
            .as_integer()
            .copied()
            .ok_or(Error::row_conversion("timestamp", "an integer"))?;

        let topic_id = row
            .get_value(2)?
            .as_integer()
            .copied()
            .ok_or(Error::row_conversion("topic_id", "an integer"))?;

        let data = take_blob(row.get_value(3)?, "data")?;

        Ok((id, timestamp, topic_id, data))
    }
}

pub(super) fn take_blob(value: turso::Value, field: &'static str) -> Result<Vec<u8>> {
    match value {
        turso::Value::Blob(data) => Ok(data),
        _ => Err(Error::row_conversion(field, "a blob")),
    }
}

impl super::Message for RawMessage {
    fn from_row(row: turso::Row) -> Result<Self, Error> {
        let (id, timestamp, topic_id, data) = Self::fields_from_row(row)?;
        Ok(Self {
            id,
            topic_id,
            timestamp,
            serialization_format: "cdr".to_owned(),
            data,
        })
    }
}