Add jiff instead of time for time parsing

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2025-01-30 21:59:59 +01:00
parent ac76c030c6
commit 51012c19a7
4 changed files with 97 additions and 26 deletions

53
Cargo.lock generated
View file

@ -231,7 +231,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
@ -247,7 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -401,6 +400,35 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jiff"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c607c728e28764fecde611a2764a3a5db19ae21dcec46f292244f5cc5c085a81"
dependencies = [
"jiff-tzdb-platform",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
"windows-sys 0.59.0",
]
[[package]]
name = "jiff-tzdb"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2cec2f5d266af45a071ece48b1fb89f3b00b2421ac3a5fe10285a6caaa60d3"
[[package]]
name = "jiff-tzdb-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a63c62e404e7b92979d2792352d885a7f8f83fd1d0d31eea582d77b2ceca697e"
dependencies = [
"jiff-tzdb",
]
[[package]]
name = "kdl"
version = "6.3.3"
@ -715,10 +743,10 @@ dependencies = [
"camino",
"clap",
"futures",
"jiff",
"kdl",
"miette",
"owo-colors",
"time",
"tokio",
"tokio-stream",
"tracing",
@ -738,6 +766,21 @@ dependencies = [
"time",
]
[[package]]
name = "portable-atomic"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
@ -840,7 +883,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1269,7 +1312,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]

View file

@ -9,10 +9,10 @@ license.workspace = true
camino = { version = "1.1.9", features = ["serde", "serde1"] }
clap = { version = "4.5.27", features = ["derive"] }
futures = "0.3.31"
jiff = "0.1.28"
kdl.workspace = true
miette = { version = "7.4.0", features = ["fancy", "syntect-highlighter"] }
owo-colors = "4.1.0"
time = { version = "0.3.37", features = ["macros", "parsing", "serde-well-known"] }
tokio = { version = "1.43.0", features = ["full"] }
tokio-stream = { version = "0.1.17", features = ["full"] }
tracing = "0.1.41"

View file

@ -6,13 +6,14 @@ use camino::Utf8PathBuf;
use clap::Parser;
use futures::StreamExt;
use futures::TryStreamExt;
use jiff::fmt::temporal::DateTimeParser;
use jiff::Timestamp;
use kdl::KdlDocument;
use kdl::KdlValue;
use miette::IntoDiagnostic;
use miette::LabeledSpan;
use miette::NamedSource;
use owo_colors::OwoColorize;
use time::OffsetDateTime;
use tokio_stream::wrappers::ReadDirStream;
use tracing::info;
@ -40,10 +41,28 @@ async fn main() -> miette::Result<()> {
#[derive(Debug)]
pub struct Record {
kind: String,
at: OffsetDateTime,
at: Timestamp,
fields: BTreeMap<String, KdlValue>,
}
fn parse_timestamp(value: &str) -> miette::Result<Timestamp> {
let parser = DateTimeParser::new();
parser
.parse_timestamp(value)
.or_else(|_| {
parser
.parse_datetime(value)
.and_then(|date| date.in_tz("UTC").map(|z| z.timestamp()))
})
.or_else(|_| {
parser
.parse_date(value)
.and_then(|date| date.in_tz("UTC").map(|z| z.timestamp()))
})
.into_diagnostic()
}
fn parse_record(
bytes: &str,
definitions: &BTreeMap<String, Vec<Definition>>,
@ -74,8 +93,7 @@ fn parse_record(
))?;
};
let Ok(at) = OffsetDateTime::parse(at, &time::format_description::well_known::Rfc3339)
else {
let Ok(at) = parse_timestamp(at) else {
return Err(miette::diagnostic!(
labels = vec![LabeledSpan::new_primary_with_span(None, at_entry.span())],
"This datetime should be a string formatted as RFC3339."
@ -100,9 +118,13 @@ fn parse_record(
let kind = &matching_def.fields[name.value()];
if !kind.is_valid(&val) {
return Err(miette::diagnostic!(
labels = vec![LabeledSpan::new_primary_with_span(None, name.span())],
if let Err(e) = kind.validate(&val) {
Err(miette::diagnostic!(
labels = vec![LabeledSpan::new_primary_with_span(
Some(String::from("here")),
name.span()
)],
help = e,
"This field has the wrong kind."
))?;
}
@ -143,9 +165,8 @@ async fn load_records(
})
.flat_map(|val| futures::stream::iter(val.transpose()))
.and_then(|(name, bytes)| async move {
Ok(parse_record(&bytes, definitions).map_err(|e| {
e.with_source_code(NamedSource::new(name, bytes).with_language("kdl"))
})?)
parse_record(&bytes, definitions)
.map_err(|e| e.with_source_code(NamedSource::new(name, bytes).with_language("kdl")))
})
.map(|val| val.map(|recs| futures::stream::iter(recs).map(Ok::<_, miette::Report>)))
.try_flatten()
@ -161,12 +182,17 @@ pub enum DefinitionKind {
OneOf(Vec<String>),
}
impl DefinitionKind {
fn is_valid(&self, val: &KdlValue) -> bool {
fn validate(&self, val: &KdlValue) -> Result<(), String> {
match self {
DefinitionKind::String => val.is_string(),
DefinitionKind::String => val
.is_string()
.then_some(())
.ok_or("Expected a string here".to_string()),
DefinitionKind::OneOf(options) => val
.as_string()
.is_some_and(|val| options.iter().any(|o| o == val)),
.is_some_and(|val| options.iter().any(|o| o == val))
.then_some(())
.ok_or_else(|| format!("Expected one of: {}", options.join(", "))),
}
}
}
@ -183,7 +209,7 @@ impl TryFrom<&str> for DefinitionKind {
#[derive(Debug)]
pub struct Definition {
since: OffsetDateTime,
since: Timestamp,
fields: HashMap<String, DefinitionKind>,
}
@ -215,10 +241,7 @@ fn parse_definition(bytes: &str) -> miette::Result<Vec<Definition>> {
))?;
};
let since = match OffsetDateTime::parse(
since,
&time::format_description::well_known::Rfc3339,
) {
let since = match parse_timestamp(since) {
Ok(since) => since,
Err(_err) => {
return Err(miette::diagnostic!(

View file

@ -1,6 +1,11 @@
changelog "2025-01-29 21:17:50+01:00" {
changelog "2025-01-29" {
title "Added parsing of plaixt definitions"
version "0.1.0"
kind "Feature"
}
changelog "2025-01-30 09:10:59+01:00" {
title "Added parsing of plaixt records"
version "0.1.0"
kind "Feature"
}