transforms/types/buffer/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::types::{Duration, Timestamp, Transform};
use core::f64;
use std::collections::BTreeMap;
mod error;
pub use error::BufferError;

type NearestTransforms<'a> = (
    Option<(&'a Timestamp, &'a Transform)>,
    Option<(&'a Timestamp, &'a Transform)>,
);
pub struct Buffer {
    data: BTreeMap<Timestamp, Transform>,
    max_age: u128,
    is_static: bool,
}

impl Buffer {
    pub fn new(max_age: f64) -> Result<Self, BufferError> {
        if max_age <= 0.0 {
            return Err(BufferError::MaxAgeInvalid(max_age, f64::INFINITY));
        }

        if max_age == f64::INFINITY {
            return Ok(Self {
                data: BTreeMap::new(),
                max_age: u128::MAX,
                is_static: false,
            });
        }

        Ok(Self {
            data: BTreeMap::new(),
            max_age: (max_age * 1e9) as u128,
            is_static: false,
        })
    }

    pub fn insert(
        &mut self,
        transform: Transform,
    ) {
        self.is_static = transform.timestamp.nanoseconds == 0;
        self.data.insert(transform.timestamp, transform);
    }

    pub fn get(
        &mut self,
        timestamp: &Timestamp,
    ) -> Result<Transform, BufferError> {
        if self.is_static {
            match self.data.get(&Timestamp { nanoseconds: 0 }) {
                Some(tf) => return Ok(tf.clone()),
                None => return Err(BufferError::NoTransformAvailable),
            }
        };

        self.delete_expired();
        let (before, after) = self.get_nearest(timestamp);

        match (before, after) {
            (Some(before), Some(after)) => Ok(Transform::interpolate(
                before.1.clone(),
                after.1.clone(),
                *timestamp,
            )?),
            _ => Err(BufferError::NoTransformAvailable),
        }
    }

    fn get_nearest(
        &self,
        timestamp: &Timestamp,
    ) -> NearestTransforms {
        let before = self.data.range(..=timestamp).next_back();

        if let Some((t, _)) = before {
            if t == timestamp {
                return (before, before);
            }
        }

        let after = self.data.range(timestamp..).next();
        (before, after)
    }

    fn delete_expired(&mut self) {
        let timestamp_threshold = Timestamp::now()
            - Duration {
                nanoseconds: self.max_age,
            };
        if let Ok(t) = timestamp_threshold {
            self.delete_before(t)
        }
    }

    fn delete_before(
        &mut self,
        timestamp: Timestamp,
    ) {
        self.data.retain(|&k, _| k >= timestamp);
    }
}

#[cfg(test)]
mod tests;