cloudfront_logs/referential/
parquet.rs

1use crate::{borrowed::UnvalidatedParquetLogline as BorrowedLine, shared::validate_line, types::*};
2
3pub use crate::types::{Datelike, Timelike};
4
5/// A (thread safe) line string
6///
7/// We use a [`Arc<str>`] over [`String`] to communicate its immutability and fixedness.
8/// (`Arc<str>`/`Box<str>`/`&str` don't carry any capacity data, only the length.)
9///
10/// While `Box<str>` is also possible, the box is not thread safe and
11/// and both types have pretty similar performance characteristics.
12pub type LineStr = Arc<str>;
13
14self_cell::self_cell!(
15    struct Container {
16        owner: LineStr,
17
18        #[covariant]
19        dependent: BorrowedLine,
20    }
21
22    impl {Debug, PartialEq}
23);
24
25impl Clone for Container {
26    fn clone(&self) -> Self {
27        let input = Arc::clone(self.borrow_owner());
28        Self::new(input, |line| {
29            let dependent = BorrowedLine::try_from(line.as_ref())
30                .expect("invalid line input despite validation");
31            dependent
32        })
33    }
34}
35
36pub type UnvalidatedLogline = Logline<Unvalidated>;
37pub type ValidatedLogline = Logline<Validated>;
38
39#[derive(Debug, Clone, PartialEq)]
40pub struct Logline<V> {
41    inner: Container,
42    _marker: PhantomData<V>,
43}
44
45impl<V> Logline<V> {
46    pub fn view(&self) -> &BorrowedLine<'_> {
47        self.inner.borrow_dependent()
48    }
49
50    pub fn as_raw(&self) -> &str {
51        self.inner.borrow_owner()
52    }
53
54    pub fn into_raw(self) -> LineStr {
55        self.inner.into_owner()
56    }
57
58    pub fn schema() -> &'static str {
59        crate::consts::parquet_schemata::V1
60    }
61
62    pub fn schema_as_type() -> parquet::schema::types::Type {
63        parquet::schema::parser::parse_message_type(crate::consts::parquet_schemata::V1).unwrap()
64    }
65}
66
67macro_rules! impl_try_from {
68    ($in:ty, $out_v:ident, $out_u:ident) => {
69        impl TryFrom<$in> for $out_v {
70            type Error = &'static str;
71
72            fn try_from(line: $in) -> Result<Self, Self::Error> {
73                let line: LineStr = line.into();
74                validate_line(&line)?;
75                let container = Container::new(line, |line| {
76                    BorrowedLine::try_from(line.as_ref())
77                        .expect("invalid line input despite validation")
78                });
79                Ok($out_v {
80                    inner: container,
81                    _marker: PhantomData,
82                })
83            }
84        }
85
86        impl TryFrom<$in> for $out_u {
87            type Error = &'static str;
88
89            fn try_from(line: $in) -> Result<Self, Self::Error> {
90                let container = Container::new(line.into(), |line| {
91                    BorrowedLine::try_from(line.as_ref())
92                        .expect("invalid line input despite validation")
93                });
94                Ok($out_u {
95                    inner: container,
96                    _marker: PhantomData,
97                })
98            }
99        }
100    };
101}
102
103impl_try_from!(&str, ValidatedLogline, UnvalidatedLogline);
104impl_try_from!(String, ValidatedLogline, UnvalidatedLogline);
105impl_try_from!(Box<str>, ValidatedLogline, UnvalidatedLogline);
106impl_try_from!(Arc<str>, ValidatedLogline, UnvalidatedLogline);