godspeed/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2//! The GodspeedOS standard library.
3//!
4//! Small, typed wrappers over the mechanisms GodspeedOS already has, so that writing a program does
5//! not start with learning a wire protocol.
6//!
7//! # The whole of it
8//!
9//! ```ignore
10//! use godspeed::{fs, io, ipc, ServiceContext};
11//!
12//! #[no_mangle]
13//! pub extern "C" fn service_main(ctx: ServiceContext) -> ! {
14//! let mut fs = fs::Fs::new(&ctx);
15//! let mut buf = [0u8; 4096];
16//!
17//! match fs.read_into("/data/hello.txt", &mut buf) {
18//! Ok(n) => io::println(&ctx, core::str::from_utf8(&buf[..n]).unwrap_or("<not utf-8>")),
19//! Err(e) => io::report(&ctx, "read", e),
20//! }
21//! ipc::park(&ctx) // finished: hold still, using no CPU (see "Why `service_main`" below)
22//! }
23//! ```
24//!
25//! # What this library will not do for you
26//!
27//! **It does not grant authority.** Every entry point takes a `&ServiceContext`, because that is
28//! where authority lives. `fs::Fs::new(&ctx)` is a convenience, not a capability: a task whose
29//! spawn request never named the filesystem as a peer (CLAUDE.md 13.6), and that holds no
30//! `ACQUIRE_ANY`, gets [`Error::Unreachable`] from it, the same as for any peer it cannot reach. There is no global, no ambient handle, and no `print!` that finds a stdout
31//! on its own - a global would be ambient authority wearing a familiar name.
32//!
33//! **It does not hide failure.** In particular it does not hide the difference between "the request
34//! never left" and "no answer came back", because those demand opposite responses and collapsing
35//! them is how a retry becomes a second delete. [`Error::retry_is_safe`] is the answer in one call.
36//!
37//! **It does not pretend there is a heap.** There is not, deliberately (CLAUDE.md ยง26.6.1), so
38//! nothing here returns an allocated `String` or `Vec`. Callers own their buffers and the bound is
39//! readable in the source. Making this look like Rust's `std` would mean trading the architecture
40//! for a familiar shape, which is the one thing this library is not for.
41//!
42//! # Why `service_main` and not `fn main`
43//!
44//! Because GodspeedOS has no terminating task yet. Every runnable thing is a service, entered at
45//! `service_main(ctx) -> !`, and of the 54 syscalls the only one that ends a task is `Kill` - which
46//! kills by name and is gated behind `service_control`, a capability no application should hold.
47//!
48//! That gap is real and is written up in `docs/stdlib-design.md` rather than papered over here. It
49//! needs one kernel change, reviewed on its own terms; this library is deliberately useful without
50//! it, and will not grow a userspace impersonation of it.
51//!
52//! # Where the unsafe lives
53//!
54//! Nowhere in this crate. `#![deny(unsafe_code)]` below, with no exception - unlike a service, this
55//! is a library and exports no `#[no_mangle]` entry symbol, so it does not need even the one
56//! `#[allow]` that services carry.
57
58#![cfg_attr(not(test), no_std)]
59#![deny(unsafe_code)]
60
61pub mod addr;
62pub mod error;
63/// Device-neutral mechanisms for drivers (`docs/driver-library.md`). Not gated on the host test build:
64/// its pure arithmetic is unit-tested there, and the SDK-dependent half gates itself.
65pub mod driver;
66
67// THE SDK-DEPENDENT HALF, and why it is not in the host test build.
68//
69// `godspeed_sdk` provides the `panic_handler`, and so does `std`. Any crate that depends on the SDK and is
70// then built for the host with `std` hits `duplicate lang item`. The SDK itself sidesteps this with
71// `cfg_attr(not(test), no_std)`, which only helps the crate being tested.
72//
73// So the split follows the pattern `kernel/src/clock.rs` already documents: the PURE logic (the
74// error model, which is most of the semantics worth testing) has no SDK import and is unit-tested
75// on the host; everything that actually talks to a service is exercised on the TARGET, where it can
76// meet a real filesystem that can really be restarted. A mock would only prove this library agrees
77// with a mock.
78#[cfg(not(test))] pub mod call;
79#[cfg(not(test))] pub mod cap;
80#[cfg(not(test))] pub mod file;
81#[cfg(not(test))] pub mod ipc;
82#[cfg(not(test))] pub mod task;
83#[cfg(not(test))] pub mod trace;
84#[cfg(not(test))] pub mod record;
85#[cfg(not(test))] pub mod fs;
86#[cfg(not(test))] pub mod io;
87#[cfg(not(test))] pub mod net;
88#[cfg(not(test))] pub mod resource;
89#[cfg(not(test))] pub mod memory;
90#[cfg(not(test))] pub mod program;
91#[cfg(not(test))] pub mod app;
92#[cfg(not(test))] pub mod handover;
93
94pub use error::Error;
95
96/// The service context, re-exported so an ordinary program never has to name `godspeed_sdk`.
97///
98/// Every program's entry point takes one, and this library said "you should not need the SDK" while
99/// requiring the SDK for the first line of every program. The Stranger Test caught that: a weak
100/// model given only the published documentation wrote `use godspeed_sdk::ServiceContext;` and
101/// recorded it as the single thing most likely to stop its program compiling.
102///
103/// It is a re-export rather than a wrapper on purpose - it is the SAME type, so a program that does
104/// reach for the SDK later is not holding two different things with one name.
105#[cfg(not(test))]
106pub use godspeed_sdk::service_context::ServiceContext;
107
108/// Everything a small program usually wants, in one `use`.
109///
110/// Deliberately tiny. A prelude that pulls in a framework is how a standard library stops being one.
111#[cfg(not(test))]
112pub mod prelude {
113 pub use crate::error::Error;
114 pub use crate::file::File;
115 pub use crate::fs::Fs;
116 pub use crate::net::Net;
117 pub use crate::io;
118 pub use godspeed_sdk::service_context::ServiceContext;
119}