///|
fn number(text : String) -> @smithy.NodeNumber {
@smithy.NodeNumber::parse(text).unwrap()
}
///|
fn integer_bounds(kind : @smithy.SimpleType) -> (String, String)? {
match kind {
Byte => Some(("-128", "127"))
Short => Some(("-32768", "32767"))
Integer => Some(("-2147483648", "2147483647"))
Long => Some(("-9223372036854775808", "9223372036854775807"))
_ => None
}
}
///|
fn numeric_bounds(
kind : @smithy.SimpleType,
value : @smithy.NodeNumber,
) -> Bool {
if integer_bounds(kind) is Some((min, max)) {
return value.is_integer() &&
value.numeric_compare(number(min)) >= 0 &&
value.numeric_compare(number(max)) <= 0
}
if kind == BigInteger {
return value.is_integer()
}
let bound = match kind {
Float => Some("340282346638528859811704183484516925440")
Double =>
Some(
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368",
)
_ => None
}
match bound {
None => true
Some(max) =>
value.numeric_compare(number("-" + max)) >= 0 &&
value.numeric_compare(number(max)) <= 0
}
}
///|
fn strict_blob_length(text : String) -> Int32? {
let bytes = @base64.decode(text, ignore_whitespace=false) catch {
_ => return None
}
if @base64.encode(bytes, padding=true) != text {
return None
}
Some(bytes.length())
}
///|
/// Positive UTC insertion dates from IERS Leap_Second.dat, Bulletin 72
/// (July 2026): https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat.
/// The initial 1972-01-01 offset is a baseline, not an inserted second.
/// Update this table when IERS announces another insertion. No negative
/// leap seconds are recorded; ordinary seconds 00..59 remain accepted.
fn positive_leap_second(year : Int32, month : Int32, day : Int32) -> Bool {
match (year, month, day) {
(1972, 6, 30)
| (1972, 12, 31)
| (1973, 12, 31)
| (1974, 12, 31)
| (1975, 12, 31)
| (1976, 12, 31)
| (1977, 12, 31)
| (1978, 12, 31)
| (1979, 12, 31)
| (1981, 6, 30)
| (1982, 6, 30)
| (1983, 6, 30)
| (1985, 6, 30)
| (1987, 12, 31)
| (1989, 12, 31)
| (1990, 12, 31)
| (1992, 6, 30)
| (1993, 6, 30)
| (1994, 6, 30)
| (1995, 12, 31)
| (1997, 6, 30)
| (1998, 12, 31)
| (2005, 12, 31)
| (2008, 12, 31)
| (2012, 6, 30)
| (2015, 6, 30)
| (2016, 12, 31) => true
_ => false
}
}
///|
fn leap_second_minute(
year : Int32,
month : Int32,
day : Int32,
hour : Int32,
minute : Int32,
offset_minutes : Int32,
) -> Bool {
// RFC 3339 offsets are local minus UTC. With offsets below 24 hours,
// the insertion minute can be 23:59 on this UTC day or the previous day.
let utc_minute = hour * 60 + minute - offset_minutes
if utc_minute == 1439 {
return positive_leap_second(year, month, day)
}
guard utc_minute == -1 else { return false }
if day > 1 {
return positive_leap_second(year, month, day - 1)
}
let (previous_year, previous_month) = if month == 1 {
(year - 1, 12)
} else {
(year, month - 1)
}
let mut previous_day = 31
while previous_day > 28 &&
!calendar_day(previous_year, previous_month, previous_day) {
previous_day -= 1
}
positive_leap_second(previous_year, previous_month, previous_day)
}
///|
fn date_time(text : String) -> Bool {
let mut i = 0
let digits = fn(start : Int32, count : Int32) -> Int32? {
if start + count > text.length() {
return None
}
let mut value = 0
for offset in 0.. 57 {
return None
}
value = value * 10 + c - 48
}
Some(value)
}
guard text.length() >= 20 &&
text.code_unit_at(4) == 45 &&
text.code_unit_at(7) == 45 &&
(text.code_unit_at(10) == 84 || text.code_unit_at(10) == 116) &&
text.code_unit_at(13) == 58 &&
text.code_unit_at(16) == 58 else {
return false
}
guard digits(0, 4) is Some(year) &&
digits(5, 2) is Some(month) &&
digits(8, 2) is Some(day) &&
calendar_day(year, month, day) &&
digits(11, 2) is Some(hour) &&
hour < 24 &&
digits(14, 2) is Some(minute) &&
minute < 60 &&
digits(17, 2) is Some(second) &&
second <= 60 else {
return false
}
i = 19
if text.code_unit_at(i) == 46 {
i += 1
let start = i
while i < text.length() &&
text.code_unit_at(i) >= 48 &&
text.code_unit_at(i) <= 57 {
i += 1
}
if i == start {
return false
}
}
guard i < text.length() else { return false }
let zone = text.code_unit_at(i)
if zone == 90 || zone == 122 {
return i + 1 == text.length() &&
(second < 60 || leap_second_minute(year, month, day, hour, minute, 0))
}
guard (zone == 43 || zone == 45) &&
i + 6 == text.length() &&
text.code_unit_at(i + 3) == 58 &&
digits(i + 1, 2) is Some(hours) &&
hours < 24 &&
digits(i + 4, 2) is Some(minutes) &&
minutes < 60 else {
return false
}
let offset = (hours * 60 + minutes) * (if zone == 43 { 1 } else { -1 })
second < 60 || leap_second_minute(year, month, day, hour, minute, offset)
}