///|
priv struct FindTimeTest {
comparison : Comparison
reference : @fsops.FileTimestamp
window : Int64
}
///|
fn parse_time_number(text : String) -> (Comparison, Double) raise FindError {
let (comparison, raw) = parse_comparison(text)
let (parsed, consumed, range_error) = @numfmt.parse_prefix(raw, Binary64)
guard consumed > 0 && consumed == raw.length() && parsed is Finite(_, _, _) else {
raise FindError("invalid finite time argument: '\{text}'")
}
let value = @string.parse_double(@numfmt.format_roundtrip(parsed, Binary64)) catch {
_ => raise FindError("invalid finite time argument: '\{text}'")
}
// xstrtod accepts underflow to zero, but rejects a nonzero range error.
if range_error && value != 0.0 {
raise FindError("time argument out of range: '\{text}'")
}
(comparison, value)
}
///|
fn find_relative_timestamp(
origin : @fsops.FileTimestamp,
offset : Double,
unit : Int64,
text : String,
) -> @fsops.FileTimestamp raise FindError {
let amount = offset * unit.to_double()
let whole = amount.trunc()
let fraction = (amount - whole) * 1000000000.0
let seconds = origin.seconds.to_double() - whole
// Reject nonfinite and out-of-range conversions instead of depending on
// the undefined floating-to-time_t conversion of a particular C build.
if amount.is_inf() ||
seconds < -9223372036854775808.0 ||
seconds >= 9223372036854775808.0 {
raise FindError("time argument exceeds signed 64-bit seconds: '\{text}'")
}
let mut seconds = seconds.to_int64()
let mut nanoseconds = (origin.nanoseconds.to_double() - fraction).to_int()
if origin.nanoseconds.to_double() < fraction {
if seconds == -9223372036854775808L {
raise FindError("time argument exceeds signed 64-bit seconds: '\{text}'")
}
seconds -= 1L
nanoseconds += 1000000000
}
// Keep GNU's one-way carry. A negative fractional offset can leave a
// nanosecond field above one second; ordered comparisons use that field.
{ seconds, nanoseconds, }
}
///|
fn parse_time_test(
text : String,
now : @fsops.FileTimestamp,
unit : Int64,
used~ : Bool = false,
) -> FindTimeTest raise FindError {
let (comparison, offset) = parse_time_number(text)
let origin : @fsops.FileTimestamp = if used {
{ seconds: 0L, nanoseconds: 0, }
} else if unit == 86400L {
{
..now,
seconds: now.seconds - (if comparison is Less { 1L } else { 86400L }),
}
} else {
now
}
{
comparison,
reference: find_relative_timestamp(origin, offset, unit, text),
window: unit,
}
}
///|
fn find_seconds_difference(left : Int64, right : Int64) -> Int64? {
if (right > 0L && left < -9223372036854775808L + right) ||
(right < 0L && left > 9223372036854775807L + right) {
None
} else {
Some(left - right)
}
}
///|
fn FindTimeTest::matches(
self : FindTimeTest,
timestamp : @fsops.FileTimestamp,
) -> Bool {
match self.comparison {
Less => @fsops.compare_timestamps(timestamp, self.reference) > 0
Greater => @fsops.compare_timestamps(timestamp, self.reference) < 0
Exact => {
guard find_seconds_difference(timestamp.seconds, self.reference.seconds)
is Some(seconds) else {
return false
}
let delta = seconds.to_double() +
1.0e-9 *
(
timestamp.nanoseconds.to_double() -
self.reference.nanoseconds.to_double()
)
delta > 0.0 && delta <= self.window.to_double()
}
}
}
///|
fn FindTimeTest::matches_used(
self : FindTimeTest,
accessed : @fsops.FileTimestamp,
changed : @fsops.FileTimestamp,
) -> Bool raise FindError {
if @fsops.compare_timestamps(accessed, changed) < 0 {
return false
}
guard find_seconds_difference(changed.seconds, accessed.seconds)
is Some(seconds) else {
raise FindError("-used timestamp difference exceeds signed 64-bit seconds")
}
let nanoseconds = changed.nanoseconds - accessed.nanoseconds
if nanoseconds < 0 {
if seconds == -9223372036854775808L {
raise FindError(
"-used timestamp difference exceeds signed 64-bit seconds",
)
}
self.matches({
seconds: seconds - 1L,
nanoseconds: nanoseconds + 1000000000,
})
} else {
self.matches({ seconds, nanoseconds, })
}
}