Skip to main content

trust_std/
lib.rs

1//! Named-argument shims over `std`.
2//!
3//! Each wrapper exists so Trust callers can write call sites with
4//! `name: value` syntax: `fs::read_to_string(path: p)` instead of the
5//! positional `std::fs::read_to_string(p)`. The wrappers carry no logic;
6//! they exist purely to make parameter names part of the signature for
7//! Trust's named-args lowering pass.
8//!
9//! This crate is `#![strict]`-marked as of RT-44. The build-time index
10//! `STD_SIGNATURES` (in `trust-lower`) used to be generated by
11//! parsing this file directly with `syn`, which would have broken the
12//! moment the file used any Trust-specific syntax. The current
13//! design generates a checked-in manifest at
14//! `crates/trust-std/std-signatures.txt` via
15//! `cargo xtask gen-std-signatures` (which lowers the source first, then
16//! parses), and `trust-lower/build.rs` reads that manifest. CI
17//! enforces freshness with `cargo xtask gen-std-signatures --check`.
18
19/// Declare a distinct newtype in one line — the ergonomic fix for R0017
20/// (`no-same-type-params`). Wrapping each same-typed parameter in its own
21/// newtype turns a silent argument swap into a compile error.
22///
23/// ```
24/// trust_std::newtype!(pub Width(u32));
25/// trust_std::newtype!(pub Height(u32));
26///
27/// pub fn make_rect(width: Width, height: Height) -> u32 {
28///     width.0 * height.0
29/// }
30/// // make_rect(Height::new(5), Width::new(10)) is now a *type error*.
31/// ```
32///
33/// Generates a tuple struct with a public field plus `new`, `into_inner`, and
34/// `From<inner>`. It derives `Debug, Clone, PartialEq` (safe for any inner
35/// type, including `f64`). Add more — `Copy`, `Eq`, `Hash`, `Ord` — with an
36/// extra `#[derive(…)]` before the declaration (don't re-list the three
37/// already derived):
38///
39/// ```
40/// trust_std::newtype!(#[derive(Copy, Eq, Hash, PartialOrd, Ord)] pub UserId(u64));
41/// ```
42#[macro_export]
43macro_rules! newtype {
44    ($(#[$meta:meta])* $vis:vis $name:ident($inner:ty)) => {
45        #[derive(Debug, Clone, PartialEq)]
46        $(#[$meta])*
47        $vis struct $name(pub $inner);
48
49        impl $name {
50            /// Wrap a raw value.
51            #[inline]
52            $vis fn new(value: $inner) -> Self {
53                $name(value)
54            }
55
56            /// Consume the newtype, returning the underlying value.
57            #[inline]
58            $vis fn into_inner(self) -> $inner {
59                self.0
60            }
61        }
62
63        impl ::core::convert::From<$inner> for $name {
64            #[inline]
65            fn from(value: $inner) -> Self {
66                $name(value)
67            }
68        }
69    };
70}
71
72pub mod fs {
73    use std::io;
74    use std::path::Path;
75
76    /// Read the entire contents of a file into a `String`.
77    pub fn read_to_string(path: &Path) -> io::Result<String> {
78        std::fs::read_to_string(path)
79    }
80
81    /// Write `contents` to a file at `path`, creating it if missing and
82    /// truncating it if it already exists.
83    pub fn write_text(path: &Path, contents: &str) -> io::Result<()> {
84        std::fs::write(path, contents)
85    }
86
87    /// Write a byte buffer to a file.
88    pub fn write_bytes(path: &Path, bytes: &[u8]) -> io::Result<()> {
89        std::fs::write(path, bytes)
90    }
91
92    /// Create a directory and any missing parents.
93    pub fn create_dir_all(path: &Path) -> io::Result<()> {
94        std::fs::create_dir_all(path)
95    }
96
97    /// Remove a single file.
98    pub fn remove_file(path: &Path) -> io::Result<()> {
99        std::fs::remove_file(path)
100    }
101
102    /// Copy `from` to `to`. Returns the number of bytes copied.
103    pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
104        std::fs::copy(from, to)
105    }
106
107    /// Rename / move `from` to `to`.
108    pub fn rename(from: &Path, to: &Path) -> io::Result<()> {
109        std::fs::rename(from, to)
110    }
111}
112
113pub mod time {
114    use std::time::Duration;
115
116    /// Build a [`Duration`] from named `secs` and `nanos`.
117    pub fn duration(secs: u64, nanos: u32) -> Duration {
118        Duration::new(secs, nanos)
119    }
120
121    /// Build a [`Duration`] from a whole number of milliseconds.
122    pub fn millis(value: u64) -> Duration {
123        Duration::from_millis(value)
124    }
125}
126
127pub mod env {
128    use std::ffi::OsString;
129
130    /// Set the value of an environment variable.
131    pub fn set_var(name: &str, value: &str) {
132        // safety: std::env::set_var is currently safe in 1.95 stable;
133        // this shim future-proofs callers if that changes.
134        // reason: documenting why this wraps a one-liner
135        unsafe {
136            std::env::set_var(name, value);
137        }
138    }
139
140    /// Get an environment variable's value, if set.
141    pub fn var(name: &str) -> Option<OsString> {
142        std::env::var_os(name)
143    }
144}
145
146pub mod thread {
147    use std::time::Duration;
148
149    /// Sleep the current thread for `duration`.
150    pub fn sleep(duration: Duration) {
151        std::thread::sleep(duration);
152    }
153}
154
155pub mod collections {
156    use std::collections::{BTreeMap, HashMap, HashSet};
157    use std::hash::Hash;
158
159    /// Insert `value` into `map` under `key`, returning the previous value.
160    pub fn insert<K: Eq + Hash, V>(map: &mut HashMap<K, V>, key: K, value: V) -> Option<V> {
161        map.insert(key, value)
162    }
163
164    /// Construct an empty [`HashMap`].
165    pub fn hashmap_new<K, V>() -> HashMap<K, V> {
166        HashMap::new()
167    }
168
169    /// Construct a [`HashMap`] pre-allocated for at least `capacity` entries.
170    pub fn hashmap_with_capacity<K, V>(capacity: usize) -> HashMap<K, V> {
171        HashMap::with_capacity(capacity)
172    }
173
174    /// Insert `value` into `map` under `key`, returning the previous value.
175    ///
176    /// Alias of [`insert`] with the more explicit `hashmap_` prefix used by
177    /// the other constructors in this module.
178    pub fn hashmap_insert<K: Eq + Hash, V>(map: &mut HashMap<K, V>, key: K, value: V) -> Option<V> {
179        map.insert(key, value)
180    }
181
182    /// Construct an empty [`BTreeMap`].
183    pub fn btreemap_new<K, V>() -> BTreeMap<K, V> {
184        BTreeMap::new()
185    }
186
187    /// Construct an empty [`HashSet`].
188    pub fn hashset_new<T>() -> HashSet<T> {
189        HashSet::new()
190    }
191}
192
193pub mod net {
194    use std::io;
195    use std::net::{TcpListener, TcpStream, UdpSocket};
196
197    /// Bind a TCP listener to `addr`.
198    pub fn tcp_listener_bind(addr: &str) -> io::Result<TcpListener> {
199        TcpListener::bind(addr)
200    }
201
202    /// Open a TCP connection to `addr`.
203    pub fn tcp_connect(addr: &str) -> io::Result<TcpStream> {
204        TcpStream::connect(addr)
205    }
206
207    /// Bind a UDP socket to `addr`.
208    pub fn udp_socket_bind(addr: &str) -> io::Result<UdpSocket> {
209        UdpSocket::bind(addr)
210    }
211}
212
213pub mod sync {
214    use std::sync::mpsc::{self, Receiver, Sender};
215    use std::sync::{Arc, Mutex, RwLock};
216
217    /// Wrap `value` in a [`Mutex`].
218    pub fn mutex_new<T>(value: T) -> Mutex<T> {
219        Mutex::new(value)
220    }
221
222    /// Wrap `value` in an [`RwLock`].
223    pub fn rwlock_new<T>(value: T) -> RwLock<T> {
224        RwLock::new(value)
225    }
226
227    /// Wrap `value` in an [`Arc`].
228    pub fn arc_new<T>(value: T) -> Arc<T> {
229        Arc::new(value)
230    }
231
232    /// Create a new asynchronous channel, returning `(sender, receiver)`.
233    ///
234    /// Takes no arguments, so named-arg lowering is a no-op here; the shim
235    /// exists for module-level discoverability alongside the other helpers.
236    pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
237        mpsc::channel()
238    }
239}
240
241pub mod process {
242    use std::process::Command;
243
244    /// Construct a [`Command`] that will spawn `program`.
245    pub fn command(program: &str) -> Command {
246        Command::new(program)
247    }
248
249    /// Append a single positional `arg` to `cmd`, returning the same `cmd`
250    /// for chaining.
251    ///
252    /// Note: `Command::arg` is defined as `&mut self -> &mut Command`, which
253    /// the named-arg lowering pass treats as a method shape. This free-fn
254    /// form re-exposes it with explicit parameter names.
255    pub fn command_arg<'a>(cmd: &'a mut Command, arg: &str) -> &'a mut Command {
256        cmd.arg(arg)
257    }
258
259    /// Set an environment variable on `cmd`, returning the same `cmd` for
260    /// chaining.
261    pub fn command_env<'a>(cmd: &'a mut Command, key: &str, value: &str) -> &'a mut Command {
262        cmd.env(key, value)
263    }
264
265    /// Terminate the current process with exit status `code`.
266    pub fn exit(code: i32) -> ! {
267        std::process::exit(code)
268    }
269}
270
271pub mod string {
272    /// Construct an empty [`String`].
273    pub fn string_new() -> String {
274        String::new()
275    }
276
277    /// Construct a [`String`] with capacity for at least `capacity` bytes.
278    pub fn string_with_capacity(capacity: usize) -> String {
279        String::with_capacity(capacity)
280    }
281}
282
283pub mod vec {
284    /// Construct an empty [`Vec`].
285    pub fn vec_new<T>() -> Vec<T> {
286        Vec::new()
287    }
288
289    /// Construct a [`Vec`] pre-allocated for at least `capacity` items.
290    pub fn vec_with_capacity<T>(capacity: usize) -> Vec<T> {
291        Vec::with_capacity(capacity)
292    }
293
294    /// Push `value` onto the end of `v`.
295    pub fn vec_push<T>(v: &mut Vec<T>, value: T) {
296        v.push(value);
297    }
298}
299
300#[cfg(test)]
301mod tests;