rs-bag 0.1.2

Read, write and modify ROS 2 rosbag2 sqlite3 (.db3) storage files
use std::ops::RangeBounds;

use crate::Result;

pub struct MessageFilter<'a> {
    pub(crate) topics: Option<Vec<&'a str>>,
    pub(crate) begin: Option<i64>,
    pub(crate) end: Option<i64>,
}

impl MessageFilter<'static> {
    pub const NONE: MessageFilter<'static> = Self {
        topics: None,
        begin: None,
        end: None,
    };
}

impl<'a> MessageFilter<'a> {
    pub fn new() -> Self {
        Self {
            topics: None,
            begin: None,
            end: None,
        }
    }
    pub fn topics<'b, I: IntoIterator<Item = &'a str>>(
        mut self,
        topics: I,
    ) -> Result<MessageFilter<'a>> {
        self.topics = Some(topics.into_iter().collect::<Vec<&str>>());
        Ok(self)
    }
    pub fn between<R: RangeBounds<i64>>(mut self, timespan: R) -> MessageFilter<'a> {
        self.begin = match timespan.start_bound() {
            std::ops::Bound::Included(i) => Some(*i),
            std::ops::Bound::Excluded(i) => Some(i + 1),
            std::ops::Bound::Unbounded => None,
        };

        self.end = match timespan.end_bound() {
            // SQL uses `m.timestamp < ?`, so Included(i) needs the cutoff after i
            std::ops::Bound::Included(i) => Some(i + 1),
            std::ops::Bound::Excluded(i) => Some(*i),
            std::ops::Bound::Unbounded => None,
        };

        self
    }
}