1use crate::{validate::validate_file, TzifError};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
4pub enum Version {
5 V1,
6 V2,
7 V3,
8 V4,
9}
10
11impl Version {
12 pub(crate) const fn from_byte(byte: u8) -> Result<Self, TzifError> {
13 match byte {
14 0 => Ok(Self::V1),
15 b'2' => Ok(Self::V2),
16 b'3' => Ok(Self::V3),
17 b'4' => Ok(Self::V4),
18 _ => Err(TzifError::InvalidVersion(byte)),
19 }
20 }
21
22 pub(crate) const fn byte(self) -> u8 {
23 match self {
24 Self::V1 => 0,
25 Self::V2 => b'2',
26 Self::V3 => b'3',
27 Self::V4 => b'4',
28 }
29 }
30
31 pub(crate) const fn is_v2_plus(self) -> bool {
32 !matches!(self, Self::V1)
33 }
34}
35
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct TzifFile {
38 pub version: Version,
39 pub v1: DataBlock,
40 pub v2_plus: Option<DataBlock>,
41 pub footer: Option<String>,
42}
43
44impl TzifFile {
45 #[must_use]
46 pub const fn v1(block: DataBlock) -> Self {
47 Self {
48 version: Version::V1,
49 v1: block,
50 v2_plus: None,
51 footer: None,
52 }
53 }
54
55 pub fn v2(v1: DataBlock, v2: DataBlock, footer: impl Into<String>) -> Self {
56 Self::v2_plus(Version::V2, v1, v2, footer)
57 }
58
59 pub fn v3(v1: DataBlock, v3: DataBlock, footer: impl Into<String>) -> Self {
60 Self::v2_plus(Version::V3, v1, v3, footer)
61 }
62
63 pub fn v4(v1: DataBlock, v4: DataBlock, footer: impl Into<String>) -> Self {
64 Self::v2_plus(Version::V4, v1, v4, footer)
65 }
66
67 pub fn validate(&self) -> Result<(), TzifError> {
74 validate_file(self)
75 }
76
77 fn v2_plus(
78 version: Version,
79 v1: DataBlock,
80 block: DataBlock,
81 footer: impl Into<String>,
82 ) -> Self {
83 Self {
84 version,
85 v1,
86 v2_plus: Some(block),
87 footer: Some(footer.into()),
88 }
89 }
90}
91
92#[derive(Clone, Debug, Default, PartialEq, Eq)]
93pub struct DataBlock {
94 pub transition_times: Vec<i64>,
95 pub transition_types: Vec<u8>,
96 pub local_time_types: Vec<LocalTimeType>,
97 pub designations: Vec<u8>,
98 pub leap_seconds: Vec<LeapSecond>,
99 pub standard_wall_indicators: Vec<bool>,
100 pub ut_local_indicators: Vec<bool>,
101}
102
103impl DataBlock {
104 pub fn new(local_time_types: Vec<LocalTimeType>, designations: impl Into<Vec<u8>>) -> Self {
105 Self {
106 local_time_types,
107 designations: designations.into(),
108 ..Self::default()
109 }
110 }
111
112 #[must_use]
113 pub fn placeholder() -> Self {
114 Self::new(
115 vec![LocalTimeType {
116 utc_offset: 0,
117 is_dst: false,
118 designation_index: 0,
119 }],
120 vec![0],
121 )
122 }
123}
124
125#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126pub struct LocalTimeType {
127 pub utc_offset: i32,
128 pub is_dst: bool,
129 pub designation_index: u8,
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq)]
133pub struct LeapSecond {
134 pub occurrence: i64,
135 pub correction: i32,
136}