Skip to content

Commit a47bb89

Browse files
Richer stdlib: sha256/sha512, base64, datetime via chrono
Eighth piece of the Python ergonomics catch-up. Three small but high-leverage stdlib additions: HASHING (via sha2 crate): sha256(text) -> 64-char hex string sha512(text) -> 128-char hex string Deterministic, NIST-standard. Common use cases (content addressing, integrity check, password hashing scaffolding) can now be done without an embedded-Python detour. BASE64 (via base64 crate, STANDARD engine): base64_encode(text) -> string base64_decode(string) -> text Round-trip identity. The decoder requires valid UTF-8 output; binary blobs that aren't UTF-8 raise an error rather than return garbage. Future work: bytes type for non-textual data. DATETIME (via chrono): now_iso() -> ISO 8601 timestamp string now_unix() -> seconds since epoch (i64) format_time(unix_seconds, fmt) -> formatted string parse_time(string, fmt) -> unix_seconds chrono::strftime-style format specifiers (%Y, %m, %d, %H, %M, %S). Tests (examples/tests/test_stdlib.omc — 12 tests, all pass): - sha256: empty string + 'hello' against canonical hex digests - sha256/sha512 length invariants (64 / 128 hex chars) - sha256 determinism + different inputs differ - base64 round-trip + known encode/decode pair + empty string - now_unix reasonable range (post-2023, pre-year-2603 sanity) - now_iso format starts with YYYY-MM-DD (regex) - format_time(0, ...) is 1970-01-01 (Unix epoch) - parse_time → format_time round-trip What this unlocks: - Content-addressed substrate identifiers (sha256 of OMC source → stable build hashes) - HTTP basic-auth header construction (base64_encode of user:pass) - Time-series substrate analysis with proper datetime parsing - Logging / instrumentation with formatted timestamps What's NOT yet in stdlib: - URL encoding (url_encode/url_decode) - Bytes type (everything strings) - MD5 (legacy; can add via md-5 crate when needed) - File globbing (glob_match) - Timezone-aware datetime ops Cargo.toml: added sha2, base64, chrono (chrono with std + clock features only — no default for serde to keep transient deps light). Regression: 240 OMC tests + 12 new stdlib = 252 OMC tests pass. All previous suites green. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent f57beb1 commit a47bb89

5 files changed

Lines changed: 375 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 189 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/tests/test_stdlib.omc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Tests for the richer stdlib: hashing, base64, datetime.
2+
3+
fn assert_eq(actual, expected, msg) {
4+
if actual != expected {
5+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
6+
}
7+
}
8+
9+
fn assert_true(cond, msg) {
10+
if !cond { test_record_failure(msg); }
11+
}
12+
13+
# ---- sha256 ----
14+
15+
fn test_sha256_empty() {
16+
# Known SHA-256 of empty string
17+
assert_eq(sha256(""),
18+
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
19+
"sha256 of empty string");
20+
}
21+
22+
fn test_sha256_hello() {
23+
assert_eq(sha256("hello"),
24+
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
25+
"sha256 of 'hello'");
26+
}
27+
28+
fn test_sha256_deterministic() {
29+
assert_eq(sha256("test"), sha256("test"), "deterministic");
30+
assert_true(sha256("a") != sha256("b"), "different inputs differ");
31+
}
32+
33+
fn test_sha256_length() {
34+
# SHA-256 always produces 64 hex chars (256 bits).
35+
assert_eq(str_len(sha256("anything")), 64, "sha256 hex is 64 chars");
36+
}
37+
38+
fn test_sha512_length() {
39+
# SHA-512 produces 128 hex chars.
40+
assert_eq(str_len(sha512("x")), 128, "sha512 hex is 128 chars");
41+
}
42+
43+
# ---- base64 ----
44+
45+
fn test_base64_roundtrip() {
46+
h s = "hello world";
47+
h encoded = base64_encode(s);
48+
h decoded = base64_decode(encoded);
49+
assert_eq(decoded, s, "base64 round-trip");
50+
}
51+
52+
fn test_base64_known() {
53+
assert_eq(base64_encode("hi"), "aGk=", "encode 'hi'");
54+
assert_eq(base64_decode("aGk="), "hi", "decode 'aGk='");
55+
}
56+
57+
fn test_base64_empty() {
58+
assert_eq(base64_encode(""), "", "empty encode");
59+
assert_eq(base64_decode(""), "", "empty decode");
60+
}
61+
62+
# ---- Datetime ----
63+
64+
fn test_now_unix_reasonable() {
65+
h now = now_unix();
66+
# Should be > 1.7e9 (post-2023) and < 2e10 (sanity upper bound)
67+
assert_true(now > 1700000000, "post-2023");
68+
assert_true(now < 20000000000, "before year 2603");
69+
}
70+
71+
fn test_now_iso_format() {
72+
h s = now_iso();
73+
# ISO 8601 should start with 4-digit year then `-`
74+
assert_true(str_len(s) > 18, "ISO string has reasonable length");
75+
assert_true(re_match("^[0-9]{4}-[0-9]{2}-[0-9]{2}", s) == 1,
76+
"ISO starts with YYYY-MM-DD");
77+
}
78+
79+
fn test_format_time_known() {
80+
# Unix epoch = 1970-01-01 00:00:00 UTC
81+
assert_eq(format_time(0, "%Y-%m-%d"), "1970-01-01", "epoch is 1970-01-01");
82+
assert_eq(format_time(0, "%H:%M:%S"), "00:00:00", "epoch time is 00:00:00");
83+
}
84+
85+
fn test_parse_format_roundtrip() {
86+
h s = "2023-06-15 10:30:00";
87+
h ts = parse_time(s, "%Y-%m-%d %H:%M:%S");
88+
h back = format_time(ts, "%Y-%m-%d %H:%M:%S");
89+
assert_eq(back, s, "parse → format round-trip");
90+
}

0 commit comments

Comments
 (0)