Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ For a standalone executable without Python, run `cargo install --path cli`. Carg

## Contributing

Install the development and documentation tools with `pip install -e '.[dev]'`. That also builds the extension and installs it in the editable package. The main commands are:
Install the development and documentation tools with `pip install -e '.[dev]'`, and install the Rust test runner with `cargo install cargo-nextest --locked`. Run `cargo develop` to build and install the extension and CLI. The main commands are:

```bash
cargo test
cargo nextest run --cargo-profile release
cargo develop
bpl -e '2×3+4'
cargo fastfmt
pytest
ship-rs-build
```

After Rust changes, run `cargo test` for the Rust tests, then `cargo develop` to install what `cargo test` built: the extension, and the native `bpl` command in your environment. Both use one compilation of each crate. `cargo develop` comes from `fastws-cli`, one of the development tools. Run `pip install -e '.[dev]'` again only when the package metadata changes. Use `cargo fastfmt`, not `cargo fmt`.
After Rust changes, run `cargo develop` to rebuild and install the extension and native `bpl` command, then `cargo nextest run --cargo-profile release` for the Rust tests. Both use the release build. `cargo develop` comes from `fastws-cli`, one of the development tools. Run `pip install -e '.[dev]'` again only when the package metadata changes. Use `cargo fastfmt`, not `cargo fmt`.

Before a release, run `bpl-tests prerelease` from the repository root. Among its steps, it writes the syntax highlighters' glyph lists and the macOS keyboard layout bundle, saves the notebooks' outputs, and runs nbdev's `prepare` to export, test and clean the notebooks and render the README. DEV.md's "Release" section lists every step.

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rust-version = "1.98"
license = "Apache-2.0"

[workspace.dependencies]
rustymath = { version = ">=0.1.56, <1", default-features = false }
rustymath = { version = ">=0.1.59, <1", default-features = false }
rustymath-buffer = ">=0.1.55, <1"
rustymath-timing = ">=0.1.56, <1"
pyo3 = ">=0.29.2, <1"
Expand Down
62 changes: 39 additions & 23 deletions DEV.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions nbs/target.qmd → TARGET.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Target: the finished core

> Historical design from the one-graph experiment, retained for rationale and comparison rather than current requirements. [Computational foundations](nbs/foundations.qmd) describes the implemented eager/Program engine.

Measure for every step, diff and review in the one-graph release. Existing code supplies behavior and reusable algorithms, not a requirement to retain its architecture. Reuse sound algorithms in their single intended homes. This file owns the current design; `archive/one-graph-2026-10-31.md` keeps reasons, evidence and history.

Goals, required behavior, acceptance criteria, budgets and explicit process rules are constraints. Parts, interfaces, algorithms and ownership describe the current working design. Continuously improve that design as implementation reveals simpler solutions, updating this document and affected consumers together. Ask Jeremy only when proceeding requires changing a constraint, information only he holds, or a substantive trade-off that cannot be resolved within the agreed priorities. A departure from the working design alone is not a blocker.
Expand Down
19 changes: 14 additions & 5 deletions cli/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ pub(crate) fn run(output: &mut impl Write) -> io::Result<()> {
let session = Session::new();
for (request, interrupt) in receive {
let id = request.as_ref().ok().and_then(|r| r["id"].as_u64());
let result = request.and_then(|r| reply(&session, &r, interrupt)).unwrap_or_else(|message| Reply::Json(basedpl::protocol::request_error(&message)));
let result = request.and_then(|r| reply(&session, &r, interrupt, output)).unwrap_or_else(|message| Reply::Json(basedpl::protocol::request_error(&message)));
if let Some(id) = id { active.lock().unwrap().remove(&id); }
serde_json::to_writer(&mut *output, &Line { id, result })?;
writeln!(output)?;
output.flush()?;
write_reply(output, id, result)?;
}
Ok(())
}
Expand All @@ -56,13 +54,24 @@ impl serde::Serialize for Line {
}
}

fn write_reply(output: &mut impl Write, id: Option<u64>, result: Reply) -> io::Result<()> {
serde_json::to_writer(&mut *output, &Line { id, result })?;
writeln!(output)?;
output.flush()
}

/// The result of one request, or why it can't run.
fn reply(session: &Session, request: &Value, interrupt: InterruptHandle) -> Result<Reply, String> {
fn reply(session: &Session, request: &Value, interrupt: InterruptHandle, output: &mut impl Write) -> Result<Reply, String> {
if request.get("id").is_some_and(|id| !id.is_u64()) { return Err("id must be a nonnegative integer".into()); }
let options = EvalOptions { interrupt, ..basedpl::protocol::options(request)? };
if let Some(case) = request.get("case") { return Ok(Reply::Json(basedpl_testkit::reference::check(case, &options.interrupt))); }
if let Some(spec) = request.get("timing") { return basedpl_testkit::timing::request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("steps") { return basedpl_testkit::timing::steps_request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("profile") {
return basedpl_testkit::timing::profile_request(spec, &options.interrupt, ||
write_reply(output, request["id"].as_u64(), Reply::Json(serde_json::json!({"ready":true,"error":null})))
.map_err(|error| error.to_string())).map(Reply::Json);
}
if let Some(spec) = request.get("costs") { return basedpl_testkit::timing::file_request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("reference") { return basedpl_testkit::reference::file_request(spec, &options.interrupt).map(Reply::Json); }
if let Some(spec) = request.get("page") { return basedpl_testkit::reference::page_request(spec, &options.interrupt, options.timeout).map(Reply::Json); }
Expand Down
Loading