1use capnp::message::TypedReader;
8use capnp::serialize::{BufferSegments, OwnedSegments};
9
10use crate::capnp::jeff_capnp;
11use crate::reader::{Module, ReadJeff};
12use crate::JeffError;
13
14#[derive(Debug, Clone)]
20pub struct Jeff<'a> {
21 module: JeffCow<'a>,
23}
24
25enum JeffCow<'a> {
28 Borrowed(TypedReader<BufferSegments<&'a [u8]>, jeff_capnp::module::Owned>),
30 Owned(TypedReader<OwnedSegments, jeff_capnp::module::Owned>),
32}
33
34impl<'a> Jeff<'a> {
35 pub const VERSION: semver::Version = crate::SCHEMA_VERSION;
40
41 pub const MIN_COMPATIBLE_VERSION: semver::Version = semver::Version::new(0, 3, 0);
43 pub const MAX_COMPATIBLE_VERSION: semver::Version = semver::Version::new(0, 3, u64::MAX);
45
46 pub fn read_slice(slice: &mut &'a [u8]) -> Result<Self, JeffError> {
51 let reader = capnp::serialize::read_message_from_flat_slice(
52 slice,
53 capnp::message::ReaderOptions::new(),
54 )?;
55 let module = reader.into_typed::<jeff_capnp::module::Owned>();
56
57 module.get()?;
59
60 let slf = Self {
61 module: JeffCow::Borrowed(module),
62 };
63 slf.check_version()?;
64 Ok(slf)
65 }
66
67 pub fn read(reader: impl std::io::Read) -> Result<Self, JeffError> {
74 let reader = capnp::serialize::read_message(reader, capnp::message::ReaderOptions::new())?;
75 let module = reader.into_typed::<jeff_capnp::module::Owned>();
76
77 module.get()?;
79
80 let slf = Self {
81 module: JeffCow::Owned(module),
82 };
83 slf.check_version()?;
84 Ok(slf)
85 }
86
87 fn check_version(&self) -> Result<(), JeffError> {
93 let version = self.module().version();
94
95 if version < Self::MIN_COMPATIBLE_VERSION {
96 return Err(JeffError::VersionTooOld {
97 v: version,
98 min: Self::MIN_COMPATIBLE_VERSION.to_string(),
99 });
100 }
101 if version > Self::MAX_COMPATIBLE_VERSION {
102 let x_if_max = |v: u64| match v {
104 u64::MAX => "x".to_string(),
105 _ => v.to_string(),
106 };
107 let max = format!(
108 "{}.{}.{}",
109 x_if_max(Self::MAX_COMPATIBLE_VERSION.major),
110 x_if_max(Self::MAX_COMPATIBLE_VERSION.minor),
111 x_if_max(Self::MAX_COMPATIBLE_VERSION.patch)
112 );
113 return Err(JeffError::VersionTooNew { v: version, max });
114 }
115 Ok(())
116 }
117}
118
119impl ReadJeff for Jeff<'_> {
120 fn module(&self) -> Module<'_> {
121 Module::read_capnp(self.module.module())
122 }
123}
124
125impl JeffCow<'_> {
126 pub fn module(&self) -> jeff_capnp::module::Reader<'_> {
128 match self {
129 Self::Borrowed(module) => module.get().expect("Root type should be correct"),
130 Self::Owned(module) => module.get().expect("Root type should be correct"),
131 }
132 }
133}
134
135impl Clone for JeffCow<'_> {
136 fn clone(&self) -> Self {
137 todo!()
138 }
139}
140
141impl std::fmt::Debug for JeffCow<'_> {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 match self {
144 Self::Borrowed(_) => f.debug_tuple("JeffCow::Borrowed").finish_non_exhaustive(),
145 Self::Owned(_) => f.debug_tuple("JeffCow::Owned").finish_non_exhaustive(),
146 }
147 }
148}
149
150#[cfg(test)]
151mod test {
152 use super::*;
153 use crate::test::entangled_qs;
154 use rstest::rstest;
155
156 #[rstest]
157 fn simple_jeff(entangled_qs: Jeff<'static>) {
158 entangled_qs.check_version().unwrap();
159 }
160}