From 684754c6cd92d02246e5974c639967a8a40720d9 Mon Sep 17 00:00:00 2001 From: Alistair Smith Date: Wed, 23 Sep 2026 18:29:15 -0700 Subject: [PATCH] format examples and programs --- .changeset/examples_formatted.md | 5 + crates/scarlet/tests/golden_examples.rs | 42 +++++++ crates/scarlet/tests/programs/bitwise.scrl | 6 +- crates/scarlet/tests/programs/crypto.scrl | 8 +- crates/scarlet/tests/programs/effects.scrl | 5 +- .../scarlet/tests/programs/hex_literals.scrl | 4 +- crates/scarlet/tests/programs/http_parse.scrl | 90 +++++++-------- .../scarlet/tests/programs/http_response.scrl | 105 ++++++++++-------- crates/scarlet/tests/programs/json.scrl | 20 ++-- crates/scarlet/tests/programs/numerics.scrl | 34 +++++- crates/scarlet/tests/programs/ports.scrl | 5 +- .../tests/programs/subject_pool_restart.scrl | 22 ++-- .../tests/programs/subject_pool_rounds.scrl | 22 ++-- .../scarlet/tests/programs/supervisors.scrl | 77 +++++++++---- examples/bench_service.scrl | 10 +- examples/chat.scrl | 7 +- examples/http_client.scrl | 6 +- examples/interpreter.scrl | 7 +- examples/money.scrl | 7 +- examples/sockets.scrl | 4 +- examples/wire_format.scrl | 7 +- 21 files changed, 315 insertions(+), 178 deletions(-) create mode 100644 .changeset/examples_formatted.md diff --git a/.changeset/examples_formatted.md b/.changeset/examples_formatted.md new file mode 100644 index 00000000..ad251b7e --- /dev/null +++ b/.changeset/examples_formatted.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +The examples and the test programs are formatted, as the stdlib now is, and a test keeps them that way. diff --git a/crates/scarlet/tests/golden_examples.rs b/crates/scarlet/tests/golden_examples.rs index 876ee785..d1ceac0a 100644 --- a/crates/scarlet/tests/golden_examples.rs +++ b/crates/scarlet/tests/golden_examples.rs @@ -349,6 +349,48 @@ suite! { ], } +/// People read these to learn how Scarlet is written, so they stay exactly as +/// `scarlet fmt` writes them, as the stdlib does. +#[test] +fn every_example_and_program_is_formatted() { + let mut unformatted: Vec = Vec::new(); + for dir in [examples_dir(), programs_dir()] { + let mut entries: Vec = walk(&dir); + entries.sort(); + for path in entries { + let src = std::fs::read_to_string(&path).expect("a source file"); + let same = matches!( + scarlet::formatter::format(&src), + scarlet::formatter::FormatResult::Formatted { output } if output == src + ); + if !same { + unformatted.push(path.display().to_string()); + } + } + } + assert!( + unformatted.is_empty(), + "not formatted; run `scarlet fmt examples crates/scarlet/tests/programs`: {unformatted:?}" + ); +} + +/// Every `.scrl` under `dir`, at any depth. +fn walk(dir: &Path) -> Vec { + let mut out = Vec::new(); + let Ok(entries) = std::fs::read_dir(dir) else { + return out; + }; + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + out.extend(walk(&path)); + } else if path.extension().is_some_and(|e| e == "scrl") { + out.push(path); + } + } + out +} + // The timing-free "it still runs" check the bench scripts depend on. #[test] fn bench_runs() { diff --git a/crates/scarlet/tests/programs/bitwise.scrl b/crates/scarlet/tests/programs/bitwise.scrl index 611cfc3b..ede4f64d 100644 --- a/crates/scarlet/tests/programs/bitwise.scrl +++ b/crates/scarlet/tests/programs/bitwise.scrl @@ -98,10 +98,10 @@ pub fn main() { println( 'de morgan: ${ok( int.bitwise_not(int.bitwise_and(12345, 6789)) == - int.bitwise_or(int.bitwise_not(12345), int.bitwise_not(6789)), + int.bitwise_or(int.bitwise_not(12345), int.bitwise_not(6789)), )} ${ok( int.bitwise_not(int.bitwise_or(-12345, 6789)) == - int.bitwise_and(int.bitwise_not(-12345), int.bitwise_not(6789)), + int.bitwise_and(int.bitwise_not(-12345), int.bitwise_not(6789)), )}', ) @@ -279,7 +279,7 @@ pub fn main() { int.bitwise_or(int.bitwise_shift_left(b2, 8), b3), ), ) == - key, + key, )}', ) } diff --git a/crates/scarlet/tests/programs/crypto.scrl b/crates/scarlet/tests/programs/crypto.scrl index 19e2d322..7bf5f2d5 100644 --- a/crates/scarlet/tests/programs/crypto.scrl +++ b/crates/scarlet/tests/programs/crypto.scrl @@ -45,10 +45,10 @@ fn hex_from(b Binary, at Int, size Int, acc Binary) Binary { b, at + 1, size, - binary.append( - acc, - <>, - ), + binary.append(acc, << + nibble(int.bitwise_shift_right(v, 4)):8, + nibble(int.bitwise_and(v, 15)):8, + >>), ) } } diff --git a/crates/scarlet/tests/programs/effects.scrl b/crates/scarlet/tests/programs/effects.scrl index e433dc70..2e272467 100644 --- a/crates/scarlet/tests/programs/effects.scrl +++ b/crates/scarlet/tests/programs/effects.scrl @@ -98,7 +98,10 @@ pub fn main() { epoch_start = time.epoch_ms() println('epoch is after 2024: ${epoch_start > 1704067200000}') println('epoch is before 2100: ${epoch_start < 4102444800000}') - println('epoch is not the monotonic clock: ${epoch_start - time.to_deadline_ms(start) > 1704067200000}') + println( + 'epoch is not the monotonic clock: ${epoch_start - time.to_deadline_ms(start) > + 1704067200000}', + ) process.sleep(50) println('slept at least 50ms: ${time.since_ms(time.monotonic(), start) >= 50}') diff --git a/crates/scarlet/tests/programs/hex_literals.scrl b/crates/scarlet/tests/programs/hex_literals.scrl index 7cd27814..0eac01b6 100644 --- a/crates/scarlet/tests/programs/hex_literals.scrl +++ b/crates/scarlet/tests/programs/hex_literals.scrl @@ -26,9 +26,7 @@ pub fn main() { println('hex: ${0xFF} ${0xff} ${0X10}') println('bin: ${0b1010} ${0B11} ${0b0}') println('sep: ${0xDE_AD_BE_EF} ${0b1111_0000}') - println( - 'eq: ${ok(0xFF == 255)} ${ok(0b1111 == 15)} ${ok(0xDE_AD_BE_EF == 3735928559)}', - ) + println('eq: ${ok(0xFF == 255)} ${ok(0b1111 == 15)} ${ok(0xDE_AD_BE_EF == 3735928559)}') println('neg: ${-0xFF} ${ok(-0xFF == -255)} ${ok(-0b1010 == -10)}') println( 'max: ${ok( diff --git a/crates/scarlet/tests/programs/http_parse.scrl b/crates/scarlet/tests/programs/http_parse.scrl index da51d140..0a30eae4 100644 --- a/crates/scarlet/tests/programs/http_parse.scrl +++ b/crates/scarlet/tests/programs/http_parse.scrl @@ -170,10 +170,9 @@ pub fn main() { // line was not the problem, so this is 431, not 414. show_parse( 'header block past 64k', - binary.append( - binary.append(<<'GET / HTTP/1.1\r\n'>>, grow(<<'X-Pad: pad\r\n'>>, 70000)), - <<'\r\n'>>, - ), + binary.append(binary.append(<<'GET / HTTP/1.1\r\n'>>, grow(<<'X-Pad: pad\r\n'>>, 70000)), << + '\r\n', + >>), ) println('') @@ -209,7 +208,8 @@ pub fn main() { nul_req = <<'GET / HTTP/1.1\r\nX-N: a\0b\r\n\r\n'>> show_parse('nul in value parses', nul_req) match h1.parse_request(nul_req, 0) { - h1.Done(_, _, _, hdrs, _, _) -> println('nul in value: headers.valid = ${headers.valid(hdrs)}') + h1.Done(_, _, _, hdrs, _, _) -> + println('nul in value: headers.valid = ${headers.valid(hdrs)}') _ -> println('nul in value: parse failed') } @@ -283,18 +283,19 @@ pub fn main() { show_field('lf in value', 'X-Ok', 'a\nb') show_field('nul in value', 'X-Ok', 'a\0b') - show_valid = fn(label String, hs Array(headers.Header)) println('${label}: ${headers.valid(hs)}') + show_valid = fn(label String, hs Array( + headers.Header, + )) println('${label}: ${headers.valid(hs)}') show_valid('valid: empty list', []) - show_valid( - 'valid: token name + clean value', - [headers.Header(name: <<'X-Ok!#\$%*+-.^_|~'>>, value: <<'fine'>>)], - ) + show_valid('valid: token name + clean value', [ + headers.Header(name: <<'X-Ok!#\$%*+-.^_|~'>>, value: <<'fine'>>), + ]) show_valid('invalid: colon in name', [headers.Header(name: <<'X:Bad'>>, value: <<'v'>>)]) show_valid('invalid: lf in value', [headers.Header(name: <<'X-Ok'>>, value: <<'a\nb'>>)]) - show_valid( - 'invalid: one bad field among good', - [headers.Header(name: <<'Good'>>, value: <<'1'>>), headers.Header(name: <<'Bad Name'>>, value: <<'2'>>)], - ) + show_valid('invalid: one bad field among good', [ + headers.Header(name: <<'Good'>>, value: <<'1'>>), + headers.Header(name: <<'Bad Name'>>, value: <<'2'>>), + ]) println('') println('== pipelined requests ==') @@ -324,44 +325,36 @@ pub fn main() { // `5 5` is the internal-space trick: a value a lenient parser reads as 5 and a // stricter one as 55 — a length disagreement between two hops is a smuggle. show_framing('spaced cl rejected', <<'POST / HTTP/1.1\r\nContent-Length: 5 5\r\n\r\n'>>) - show_framing( - 'overflow rejected', - <<'POST / HTTP/1.1\r\nContent-Length: 99999999999999999999\r\n\r\n'>>, - ) - show_framing( - 'duplicate cl rejected', - <<'POST / HTTP/1.1\r\nContent-Length: 5\r\nContent-Length: 5\r\n\r\n'>>, - ) + show_framing('overflow rejected', << + 'POST / HTTP/1.1\r\nContent-Length: 99999999999999999999\r\n\r\n', + >>) + show_framing('duplicate cl rejected', << + 'POST / HTTP/1.1\r\nContent-Length: 5\r\nContent-Length: 5\r\n\r\n', + >>) show_framing('te chunked', <<'POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n'>>) - show_framing( - 'te chunked case-insensitive', - <<'POST / HTTP/1.1\r\ntransfer-encoding: CHUNKED\r\n\r\n'>>, - ) + show_framing('te chunked case-insensitive', << + 'POST / HTTP/1.1\r\ntransfer-encoding: CHUNKED\r\n\r\n', + >>) // The head parser trims OWS around a value, so a padded `chunked` still frames. - show_framing( - 'te chunked with ows', - <<'POST / HTTP/1.1\r\nTransfer-Encoding: chunked \r\n\r\n'>>, - ) + show_framing('te chunked with ows', << + 'POST / HTTP/1.1\r\nTransfer-Encoding: chunked \r\n\r\n', + >>) show_framing('te gzip unimplemented', <<'POST / HTTP/1.1\r\nTransfer-Encoding: gzip\r\n\r\n'>>) - show_framing( - 'te coding list unimplemented', - <<'POST / HTTP/1.1\r\nTransfer-Encoding: gzip, chunked\r\n\r\n'>>, - ) - show_framing( - 'te identity unimplemented', - <<'POST / HTTP/1.1\r\nTransfer-Encoding: identity\r\n\r\n'>>, - ) + show_framing('te coding list unimplemented', << + 'POST / HTTP/1.1\r\nTransfer-Encoding: gzip, chunked\r\n\r\n', + >>) + show_framing('te identity unimplemented', << + 'POST / HTTP/1.1\r\nTransfer-Encoding: identity\r\n\r\n', + >>) show_framing('empty te unimplemented', <<'POST / HTTP/1.1\r\nTransfer-Encoding:\r\n\r\n'>>) // Even two IDENTICAL `chunked` fields are refused: a repeated Transfer-Encoding // is exactly the shape a front-end/back-end framing disagreement is built from. - show_framing( - 'repeated te chunked unimplemented', - <<'POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nTransfer-Encoding: chunked\r\n\r\n'>>, - ) - show_framing( - 'te + cl conflict', - <<'POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nContent-Length: 5\r\n\r\n'>>, - ) + show_framing('repeated te chunked unimplemented', << + 'POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nTransfer-Encoding: chunked\r\n\r\n', + >>) + show_framing('te + cl conflict', << + 'POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nContent-Length: 5\r\n\r\n', + >>) println('') println('== chunked body decode ==') @@ -509,7 +502,10 @@ pub fn main() { show_collect('failing body propagates', fn() Err(error.UnexpectedEof), 1024) three_chunks = fn() Ok( - body.Chunk(<<'ab'>>, fn() Ok(body.Chunk(<<'cd'>>, fn() Ok(body.Chunk(<<'ef'>>, body.empty()))))), + body.Chunk( + <<'ab'>>, + fn() Ok(body.Chunk(<<'cd'>>, fn() Ok(body.Chunk(<<'ef'>>, body.empty())))), + ), ) show_buffered = fn(label String, b body.Body) { out = match body.take_buffered(b) { diff --git a/crates/scarlet/tests/programs/http_response.scrl b/crates/scarlet/tests/programs/http_response.scrl index fbc098c9..084b05b2 100644 --- a/crates/scarlet/tests/programs/http_response.scrl +++ b/crates/scarlet/tests/programs/http_response.scrl @@ -111,9 +111,9 @@ fn show_response_framing(label String, code Int, input Binary) Nil { fn show_url(text String) Nil { out = match url.parse(text) { Ok(u) -> - '${u.scheme} host=${u.host} port=${u.port} target=${q(u.target)} host-field=${q( - url.authority(u), - )}' + '${u.scheme} host=${u.host} port=${u.port} target=${q( + u.target, + )} host-field=${q(url.authority(u))}' Err(e) -> 'Err ${string.inspect(e)}' } println('${text} -> ${out}') @@ -208,9 +208,9 @@ fn show_exchange(label String, req_url String, method Binary, script Binary, chu req = client.Request(method: method, url: u, headers: [], body: <<>>) out = match client.send(io, req) { Ok(r) -> - '${r.status} reason=${q(r.reason)} headers=${array.length( - r.headers, - )} body=${q(r.body)}' + '${r.status} reason=${q( + r.reason, + )} headers=${array.length(r.headers)} body=${q(r.body)}' Err(e) -> 'Err ${string.inspect(e)}' } stop(inbox) @@ -222,12 +222,9 @@ fn show_exchange(label String, req_url String, method Binary, script Binary, chu fn show_bounded(label String, script Binary, max_body Int) Nil { inbox = scripted(script) io = wire_io(inbox, 65536) - u = url.parse('http://example.com/a') or url.Url( - scheme: url.Http, - host: 'x', - port: 80, - target: <<'/'>>, - ) + u = url.parse( + 'http://example.com/a', + ) or url.Url(scheme: url.Http, host: 'x', port: 80, target: <<'/'>>) req = client.Request(method: <<'GET'>>, url: u, headers: [], body: <<>>) out = match client.send_bounded(io, req, max_body) { Ok(r) -> '${r.status} body=${q(r.body)}' @@ -239,7 +236,13 @@ fn show_bounded(label String, script Binary, max_body Int) Nil { // The request head is asserted as bytes: the routing point may not quietly // change what goes on the wire. -fn show_written(label String, req_url String, method Binary, extra Array(headers.Header), body Binary) Nil { +fn show_written( + label String, + req_url String, + method Binary, + extra Array(headers.Header), + body Binary, +) Nil { match url.parse(req_url) { Err(e) -> println('${label}: url Err ${string.inspect(e)}') Ok(u) -> { @@ -282,7 +285,21 @@ pub fn main() { show_response('no space after version', <<'HTTP/1.1_200 OK\r\n\r\n'>>) show_response('junk before the reason', <<'HTTP/1.1 200_OK\r\n\r\n'>>) show_response('not HTTP at all', <<'ICY 200 OK\r\n\r\n'>>) - show_response('binary junk (a TLS record header)', <<22, 3, 1, 0, 100, 1, 0, 0, 96, 3, 3, 13, 10>>) + show_response('binary junk (a TLS record header)', << + 22, + 3, + 1, + 0, + 100, + 1, + 0, + 0, + 96, + 3, + 3, + 13, + 10, + >>) // `HTTP/` and a version we do not speak is a DIFFERENT answer from "not // HTTP/1": one means retry with another protocol, the other means this peer is // not speaking HTTP/1 at all. @@ -336,34 +353,32 @@ pub fn main() { // every close-framed reply to empty. show_response_framing('no framing fields -> until close', 200, <<'HTTP/1.1 200 OK\r\n\r\n'>>) show_response_framing('content-length', 200, <<'HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n'>>) - show_response_framing( - 'chunked', - 200, - <<'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n'>>, - ) + show_response_framing('chunked', 200, << + 'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n', + >>) // 1xx / 204 / 304 have no body whatever the fields claim. - show_response_framing('204 with a content-length', 204, <<'HTTP/1.1 204 No Content\r\nContent-Length: 9\r\n\r\n'>>) - show_response_framing('304 with a content-length', 304, <<'HTTP/1.1 304 Not Modified\r\nContent-Length: 9\r\n\r\n'>>) + show_response_framing('204 with a content-length', 204, << + 'HTTP/1.1 204 No Content\r\nContent-Length: 9\r\n\r\n', + >>) + show_response_framing('304 with a content-length', 304, << + 'HTTP/1.1 304 Not Modified\r\nContent-Length: 9\r\n\r\n', + >>) show_response_framing('100 continue', 100, <<'HTTP/1.1 100 Continue\r\n\r\n'>>) - show_response_framing('199 is still 1xx', 199, <<'HTTP/1.1 199 Early\r\nContent-Length: 4\r\n\r\n'>>) + show_response_framing('199 is still 1xx', 199, << + 'HTTP/1.1 199 Early\r\nContent-Length: 4\r\n\r\n', + >>) show_response_framing('200 is not', 200, <<'HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n'>>) // The smuggling conflicts are rejected once, in h1.framing, for both // directions — a response cannot claim both framings either. - show_response_framing( - 'content-length AND chunked', - 200, - <<'HTTP/1.1 200 OK\r\nContent-Length: 4\r\nTransfer-Encoding: chunked\r\n\r\n'>>, - ) - show_response_framing( - 'unknown transfer coding', - 200, - <<'HTTP/1.1 200 OK\r\nTransfer-Encoding: gzip\r\n\r\n'>>, - ) - show_response_framing( - 'two disagreeing content-lengths', - 200, - <<'HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Length: 5\r\n\r\n'>>, - ) + show_response_framing('content-length AND chunked', 200, << + 'HTTP/1.1 200 OK\r\nContent-Length: 4\r\nTransfer-Encoding: chunked\r\n\r\n', + >>) + show_response_framing('unknown transfer coding', 200, << + 'HTTP/1.1 200 OK\r\nTransfer-Encoding: gzip\r\n\r\n', + >>) + show_response_framing('two disagreeing content-lengths', 200, << + 'HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Length: 5\r\n\r\n', + >>) println('') println('== url ==') @@ -419,7 +434,9 @@ pub fn main() { 'chunked body', 'http://example.com/a', <<'GET'>>, - <<'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n'>>, + << + 'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n', + >>, 3, ) show_exchange( @@ -457,7 +474,9 @@ pub fn main() { 'two interim responses', 'http://example.com/a', <<'GET'>>, - <<'HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 103 Early Hints\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi'>>, + << + 'HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 103 Early Hints\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi', + >>, 65536, ) @@ -479,13 +498,7 @@ pub fn main() { <<'HTTP/1.1 200 OK\r\nContent-Le'>>, 65536, ) - show_exchange( - 'peer closes with nothing at all', - 'http://example.com/a', - <<'GET'>>, - <<>>, - 65536, - ) + show_exchange('peer closes with nothing at all', 'http://example.com/a', <<'GET'>>, <<>>, 65536) show_exchange( 'malformed status line', 'http://example.com/a', diff --git a/crates/scarlet/tests/programs/json.scrl b/crates/scarlet/tests/programs/json.scrl index 8335405b..3bb87d48 100644 --- a/crates/scarlet/tests/programs/json.scrl +++ b/crates/scarlet/tests/programs/json.scrl @@ -364,17 +364,15 @@ pub fn main() { println('') println('-- encode and round trip --') - built = json.Object( - [ - ('name', json.Str('ada')), - ('id', json.Integer(1070000000000000001)), - ('score', json.Real(9.5)), - ('active', json.Boolean(True)), - ('tags', json.List([json.Str('a'), json.Str('b')])), - ('nickname', json.Null), - ('empty', json.Object([])), - ], - ) + built = json.Object([ + ('name', json.Str('ada')), + ('id', json.Integer(1070000000000000001)), + ('score', json.Real(9.5)), + ('active', json.Boolean(True)), + ('tags', json.List([json.Str('a'), json.Str('b')])), + ('nickname', json.Null), + ('empty', json.Object([])), + ]) line('encoded ', json.encode(built)) diff --git a/crates/scarlet/tests/programs/numerics.scrl b/crates/scarlet/tests/programs/numerics.scrl index f5de7d88..1b9922b4 100644 --- a/crates/scarlet/tests/programs/numerics.scrl +++ b/crates/scarlet/tests/programs/numerics.scrl @@ -76,8 +76,16 @@ pub fn main() { // The checked forms answer `Err(Nil)` for a zero divisor and otherwise // agree with the operators, sign rules included. - println('checked div: ${string.inspect(int.divide(p7, p2))} ${string.inspect(int.divide(n7, p2))} ${string.inspect(int.divide(p7, 0))}') - println('checked rem: ${string.inspect(int.remainder(p7, p2))} ${string.inspect(int.remainder(n7, p2))} ${string.inspect(int.remainder(p7, 0))}') + println( + 'checked div: ${string.inspect( + int.divide(p7, p2), + )} ${string.inspect(int.divide(n7, p2))} ${string.inspect(int.divide(p7, 0))}', + ) + println( + 'checked rem: ${string.inspect( + int.remainder(p7, p2), + )} ${string.inspect(int.remainder(n7, p2))} ${string.inspect(int.remainder(p7, 0))}', + ) // --- Float: formatting and non-finite collapse ---------------------------- @@ -120,9 +128,21 @@ pub fn main() { // unlike it, round-trips `min_value`: its magnitude has no positive Int // to delegate the unsigned parse to, which `parse_signed`'s // strip-the-sign-then-negate scheme cannot represent. - println('from_string: ${string.inspect(int.from_string('42'))} ${string.inspect(int.from_string('-42'))} ${string.inspect(int.from_string('+7'))}') - println('from_string rejects: ${string.inspect(int.from_string(''))} ${string.inspect(int.from_string('12abc'))} ${string.inspect(int.from_string(' 1'))}') - println('from_string min round trip: ${string.inspect(int.from_string(int.to_string(int.min_value)))}') + println( + 'from_string: ${string.inspect( + int.from_string('42'), + )} ${string.inspect(int.from_string('-42'))} ${string.inspect(int.from_string('+7'))}', + ) + println( + 'from_string rejects: ${string.inspect( + int.from_string(''), + )} ${string.inspect(int.from_string('12abc'))} ${string.inspect(int.from_string(' 1'))}', + ) + println( + 'from_string min round trip: ${string.inspect( + int.from_string(int.to_string(int.min_value)), + )}', + ) println('hex: ${string.inspect(binary.to_string(binary.from_int_ascii(255, binary.Hex)))}') println('hex parse: ${string.inspect(binary.parse_int(<<'ff'>>, binary.Hex))}') @@ -147,7 +167,9 @@ pub fn main() { up_tie = decimal.to_string(decimal.round(decimal.new(2355, 3), 2)) println('round half even: ${down_tie} ${up_tie}') println( - 'round half up: ${decimal.to_string(decimal.round_with(decimal.new(2345, 3), 2, decimal.HalfUp))}', + 'round half up: ${decimal.to_string( + decimal.round_with(decimal.new(2345, 3), 2, decimal.HalfUp), + )}', ) toward_zero = decimal.round_with(decimal.new(-2349, 3), 2, decimal.Down) toward_neg_inf = decimal.round_with(decimal.new(-2341, 3), 2, decimal.Floor) diff --git a/crates/scarlet/tests/programs/ports.scrl b/crates/scarlet/tests/programs/ports.scrl index ece27b32..829c560c 100644 --- a/crates/scarlet/tests/programs/ports.scrl +++ b/crates/scarlet/tests/programs/ports.scrl @@ -81,7 +81,10 @@ pub fn main() { match port.spawn('sleep', ['30']) { Ok(p) -> - check('a lingering child is terminated on close', port.close(p) == Ok(port.Signaled(15))) + check( + 'a lingering child is terminated on close', + port.close(p) == Ok(port.Signaled(15)), + ) Err(e) -> println('FAIL spawn sleep: ${string.inspect(e)}') } diff --git a/crates/scarlet/tests/programs/subject_pool_restart.scrl b/crates/scarlet/tests/programs/subject_pool_restart.scrl index 354761fb..ef6c390a 100644 --- a/crates/scarlet/tests/programs/subject_pool_restart.scrl +++ b/crates/scarlet/tests/programs/subject_pool_restart.scrl @@ -29,16 +29,11 @@ type Request { fn ask(gateway process.Subject(Request), next fn(Int) Result(a, String)) Result(a, String) { reply = process.subject() - process.send( - gateway, - Run( - job: Job(run: fn(lease) { - outcome = bind(lease, next) - process.send(reply, outcome) - health(outcome) - }), - ), - ) + process.send(gateway, Run(job: Job(run: fn(lease) { + outcome = bind(lease, next) + process.send(reply, outcome) + health(outcome) + }))) process.receive(reply) } @@ -56,7 +51,12 @@ fn health(outcome Result(a, String)) Health { } } -fn labour(gateway process.Subject(Request), inbox process.Subject(Task), held Option(Int), seed Int) Nil { +fn labour( + gateway process.Subject(Request), + inbox process.Subject(Task), + held Option(Int), + seed Int, +) Nil { match process.receive(inbox) { Quit -> Nil Work(job) -> { diff --git a/crates/scarlet/tests/programs/subject_pool_rounds.scrl b/crates/scarlet/tests/programs/subject_pool_rounds.scrl index 162e55ef..6a7b8786 100644 --- a/crates/scarlet/tests/programs/subject_pool_rounds.scrl +++ b/crates/scarlet/tests/programs/subject_pool_rounds.scrl @@ -33,16 +33,11 @@ type Request { fn ask(gateway process.Subject(Request), next fn(Int) Result(a, String)) Result(a, String) { reply = process.subject() - process.send( - gateway, - Run( - job: Job(run: fn(lease) { - outcome = bind(lease, next) - process.send(reply, outcome) - health(outcome) - }), - ), - ) + process.send(gateway, Run(job: Job(run: fn(lease) { + outcome = bind(lease, next) + process.send(reply, outcome) + health(outcome) + }))) process.receive(reply) } @@ -60,7 +55,12 @@ fn health(outcome Result(a, String)) Health { } } -fn labour(gateway process.Subject(Request), inbox process.Subject(Task), held Option(Int), seed Int) Nil { +fn labour( + gateway process.Subject(Request), + inbox process.Subject(Task), + held Option(Int), + seed Int, +) Nil { match process.receive(inbox) { Quit -> Nil Work(job) -> { diff --git a/crates/scarlet/tests/programs/supervisors.scrl b/crates/scarlet/tests/programs/supervisors.scrl index 83e7bf70..825bf03b 100644 --- a/crates/scarlet/tests/programs/supervisors.scrl +++ b/crates/scarlet/tests/programs/supervisors.scrl @@ -176,9 +176,24 @@ fn scenarios() Nil { // One-for-all: siblings are closed in reverse order, then all restart. group = process.supervisor_in(app, process.OneForAll(restarts: 10, within_ms: 60000)) - g1 = process.worker(group, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('g1', log)) - g2 = process.worker(group, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('g2', log)) - g3 = process.worker(group, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('g3', log)) + g1 = process.worker( + group, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('g1', log), + ) + g2 = process.worker( + group, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('g2', log), + ) + g3 = process.worker( + group, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('g3', log), + ) _ = take(log, 3, []) g1_pid = whoami(g1) g2_pid = whoami(g2) @@ -219,9 +234,24 @@ fn scenarios() Nil { // Rest-for-one: only the workers declared after the dead one move. rest = process.supervisor_in(app, process.RestForOne(restarts: 10, within_ms: 60000)) - r1 = process.worker(rest, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('r1', log)) - r2 = process.worker(rest, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('r2', log)) - r3 = process.worker(rest, process.Permanent, process.Ask(Close, grace_ms: 1000), reporting('r3', log)) + r1 = process.worker( + rest, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('r1', log), + ) + r2 = process.worker( + rest, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('r2', log), + ) + r3 = process.worker( + rest, + process.Permanent, + process.Ask(Close, grace_ms: 1000), + reporting('r3', log), + ) _ = take(log, 3, []) r1_pid = whoami(r1) r2_pid = whoami(r2) @@ -235,11 +265,13 @@ fn scenarios() Nil { check('the earlier sibling was not touched', whoami(r1) == r1_pid) check( 'children lists every worker', - array.map(process.children(rest.supervised), fn( - c, - ) c == process.supervised(r1) || c == process.supervised(r2) || - c == process.supervised(r3)) == - [True, True, True], + array.map( + process.children(rest.supervised), + fn(c) c == process.supervised(r1) || + c == process.supervised(r2) || + c == process.supervised(r3), + ) == + [True, True, True], ) // A factory: one member per key, restarted in place, keys freed on exit. @@ -310,10 +342,10 @@ fn scenarios() Nil { check( 'a watch reports the exit', first.supervised == place && - match first.ended { - process.Exited(process.Killed) -> True - _ -> False - }, + match first.ended { + process.Exited(process.Killed) -> True + _ -> False + }, ) check('and that it was restarted on the spot', first.status == process.Running) _ = take(log, 1, []) @@ -336,10 +368,10 @@ fn scenarios() Nil { check( 'a final exit reports Gone', last.status == process.Gone && - match last.ended { - process.Exited(process.Normal) -> True - _ -> False - }, + match last.ended { + process.Exited(process.Normal) -> True + _ -> False + }, ) check('watching a place that is gone reports so at once', { _ = process.watch(process.supervised(v), events, fn(e) e) @@ -371,7 +403,12 @@ fn scenarios() Nil { // An Ask shutdown is delivered ahead of a backlog. pair = process.supervisor_in(app, process.OneForAll(restarts: 5, within_ms: 60000)) - slow = process.worker(pair, process.Permanent, process.Ask(Close, grace_ms: 5000), slow_worker(log)) + slow = process.worker( + pair, + process.Permanent, + process.Ask(Close, grace_ms: 5000), + slow_worker(log), + ) trigger = process.permanent(pair, reporting('trigger', log)) _ = take(log, 2, []) // Queue up slow work, then have the group stop the slow worker: the diff --git a/examples/bench_service.scrl b/examples/bench_service.scrl index 2573b01b..070972fa 100644 --- a/examples/bench_service.scrl +++ b/examples/bench_service.scrl @@ -54,7 +54,6 @@ fn sign(user Binary) Int { checksum(binary.append(SECRET, user)) } - fn make_user(i Int) User { name = 'user${i}' User( @@ -94,7 +93,6 @@ fn build_tables(i Int, n Int, t Tables) Tables { } } - const AMP = <<'&'>> const EQ = <<'='>> const SEMI = <<';'>> @@ -128,7 +126,9 @@ fn scan_pairs( None -> n } match binary.index_of(b, EQ, start) { - Some(e) -> match ( + Some( + e, + ) -> match ( binary.slice_bytes(b, start, e - start), binary.slice_bytes(b, e + 1, end - e - 1), ) { @@ -276,8 +276,8 @@ fn route(req http.Request, t Tables) http.Response { <<'/'>> -> respond(200, VAL_TEXT, 'hello') <<'/me'>> -> handle_me(req, t) _ -> match binary.slice_bytes(path, 0, USERS_PREFIX_LEN) { - Ok(prefix) if prefix == USERS_PREFIX && - binary.byte_size(path) > USERS_PREFIX_LEN -> handle_user_by_id(path, t) + Ok(prefix) if prefix == USERS_PREFIX && binary.byte_size(path) > USERS_PREFIX_LEN -> + handle_user_by_id(path, t) _ -> json(404, '{"error":"not found"}') } } diff --git a/examples/chat.scrl b/examples/chat.scrl index 83ffda0a..ee77e234 100644 --- a/examples/chat.scrl +++ b/examples/chat.scrl @@ -130,10 +130,9 @@ fn tree_frame(r Room) Binary { const HELLO = <<'retry: 1000\n\n'>> const PING = <<': ping\n\n'>> -const RESTARTED = sse( - 'system', - ['the room process crashed and was restarted; this tab rejoined it'], -) +const RESTARTED = sse('system', [ + 'the room process crashed and was restarted; this tab rejoined it', +]) // The tree, as text diff --git a/examples/http_client.scrl b/examples/http_client.scrl index 439c0517..55da05a2 100644 --- a/examples/http_client.scrl +++ b/examples/http_client.scrl @@ -114,7 +114,11 @@ fn counted(what String, r Result(body.Drained, body.DrainError)) Nil { } } -fn read_head(sock socket.Socket, buf Binary, deadline time.Instant) Result((Binary, h1.Parsed), error.NetError) { +fn read_head( + sock socket.Socket, + buf Binary, + deadline time.Instant, +) Result((Binary, h1.Parsed), error.NetError) { match h1.parse_request(buf, 0) { h1.NeedMore -> match socket.read_until(sock, HEAD_READ, deadline) { Ok(socket.Data(chunk)) -> read_head(sock, binary.append(buf, chunk), deadline) diff --git a/examples/interpreter.scrl b/examples/interpreter.scrl index c63480bf..e32223e0 100644 --- a/examples/interpreter.scrl +++ b/examples/interpreter.scrl @@ -215,7 +215,12 @@ fn describe(tokens Array(Token), env map.Map(String, Int)) Result(String, String '${show(e)} = ${v}' } -fn bind(env map.Map(String, Int), line String, name String, rest Array(Token)) map.Map(String, Int) { +fn bind( + env map.Map(String, Int), + line String, + name String, + rest Array(Token), +) map.Map(String, Int) { match result.then(parse(rest), fn(e) evaluate(e, env)) { Ok(v) -> { report(line, Ok('${name} = ${v}')) diff --git a/examples/money.scrl b/examples/money.scrl index e93e9cc4..f0886c30 100644 --- a/examples/money.scrl +++ b/examples/money.scrl @@ -39,7 +39,12 @@ fn tax(u Usd, rate decimal.Decimal) Usd { // Splits into n shares that sum back to the total. Leftover cents go first. fn split(total Usd, n Int) Array(Usd) { - base = decimal.div_with(amount(total), decimal.from_int(n), 2, decimal.Down) or decimal.from_int(0) + base = decimal.div_with( + amount(total), + decimal.from_int(n), + 2, + decimal.Down, + ) or decimal.from_int(0) leftover = decimal.units(decimal.sub(amount(total), decimal.mul(base, decimal.from_int(n)))) shares(base, leftover, n) } diff --git a/examples/sockets.scrl b/examples/sockets.scrl index 90c7acf2..aebca8ab 100644 --- a/examples/sockets.scrl +++ b/examples/sockets.scrl @@ -35,7 +35,9 @@ fn serve_one(sock socket.Socket) Nil { fn read_frame(sock socket.Socket) Result(Binary, error.NetError) { head <- result.then(socket.read_exact(sock, HEADER_BYTES)) - length <- result.then(result.replace_err(binary.parse_int(head, binary.Dec), error.UnexpectedEof)) + length <- result.then( + result.replace_err(binary.parse_int(head, binary.Dec), error.UnexpectedEof), + ) socket.read_exact(sock, length) } diff --git a/examples/wire_format.scrl b/examples/wire_format.scrl index 05c78ba5..e2d89d11 100644 --- a/examples/wire_format.scrl +++ b/examples/wire_format.scrl @@ -229,7 +229,12 @@ pub fn main() { println('255 to Dec ascii: ${ascii(255, binary.Dec)}') println('255 to Hex ascii: ${ascii(255, binary.Hex)}') - println('hex ascii round trip: ${binary.parse_int(binary.from_int_ascii(4210, binary.Hex), binary.Hex)}') + println( + 'hex ascii round trip: ${binary.parse_int( + binary.from_int_ascii(4210, binary.Hex), + binary.Hex, + )}', + ) println('slice bits 0..4: ${binary.slice_bits(headers, 0, 4)}') println('slice bits 8000..8: ${binary.slice_bits(headers, 8000, 8)}')