Skip to main content

stak/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
3
4pub mod device {
5    //! I/O devices.
6    //!
7    //! ## Examples
8    //!
9    //! ### Communication via standard I/O
10    //!
11    //! You can pass in-memory standard input and output to Scheme scripts for
12    //! communicate information between Rust and Scheme.
13    //!
14    //! ```rust
15    //! use core::{
16    //!     error::Error,
17    //!     str::{self, FromStr},
18    //! };
19    //! use stak::{
20    //!     device::ReadWriteDevice,
21    //!     file::VoidFileSystem,
22    //!     include_module,
23    //!     module::Module,
24    //!     process_context::VoidProcessContext,
25    //!     r7rs::{SmallError, SmallPrimitiveSet},
26    //!     time::VoidClock,
27    //!     vm::Vm,
28    //! };
29    //!
30    //! const BUFFER_SIZE: usize = 1 << 8;
31    //! const HEAP_SIZE: usize = 1 << 16;
32    //!
33    //! fn main() -> Result<(), Box<dyn Error>> {
34    //!     let input = 15;
35    //!     let mut output = vec![];
36    //!     let mut error = vec![];
37    //!
38    //!     run(
39    //!         &include_module!("fibonacci.scm").bytecode(),
40    //!         input.to_string().as_bytes(),
41    //!         &mut output,
42    //!         &mut error,
43    //!     )?;
44    //!
45    //!     // If stderr is not empty, we assume that some error has occurred.
46    //!     if !error.is_empty() {
47    //!         return Err(str::from_utf8(&error)?.into());
48    //!     }
49    //!
50    //!     // Decode and test the output.
51    //!     assert_eq!(isize::from_str(&str::from_utf8(&output)?)?, 610);
52    //!
53    //!     Ok(())
54    //! }
55    //!
56    //! fn run(
57    //!     bytecode: &[u8],
58    //!     input: &[u8],
59    //!     output: &mut Vec<u8>,
60    //!     error: &mut Vec<u8>,
61    //! ) -> Result<(), SmallError> {
62    //!     let mut heap = [Default::default(); HEAP_SIZE];
63    //!     let mut vm = Vm::new(
64    //!         &mut heap,
65    //!         SmallPrimitiveSet::new(
66    //!             // Create and attach an in-memory I/O device.
67    //!             ReadWriteDevice::new(input, output, error),
68    //!             VoidFileSystem::new(),
69    //!             VoidProcessContext::new(),
70    //!             VoidClock::new(),
71    //!         ),
72    //!     )?;
73    //!
74    //!     vm.run(bytecode.iter().copied())
75    //! }
76    //! ```
77
78    pub use stak_device::*;
79}
80
81#[cfg(feature = "alloc")]
82pub mod dynamic {
83    //! Dynamically-defined primitives.
84
85    pub use stak_dynamic::*;
86}
87
88#[cfg(feature = "alloc")]
89pub mod engine {
90    //! A scripting engine.
91
92    pub use stak_engine::*;
93}
94
95pub mod file {
96    //! File systems.
97
98    pub use stak_file::*;
99}
100
101pub mod module {
102    //! Modules.
103
104    pub use stak_module::*;
105}
106
107pub mod process_context {
108    //! Process context.
109
110    pub use stak_process_context::*;
111}
112
113pub mod r7rs {
114    //! Primitives for R7RS Scheme.
115
116    pub use stak_r7rs::*;
117}
118
119pub mod sac {
120    //! Standalone complex.
121
122    pub use stak_sac::*;
123}
124
125pub mod time {
126    //! Time measurement.
127
128    pub use stak_time::*;
129}
130
131pub mod vm {
132    //! A virtual machine and its runtime values.
133    //!
134    //! # Examples
135    //!
136    //! ## Embedding Scheme scripts in Rust with a custom virtual machine
137    //!
138    //! First, prepare a Scheme script named `src/hello.scm`.
139    //!
140    //! ```scheme
141    //! (import (scheme base))
142    //!
143    //! (write-string "Hello, world!\n")
144    //! ```
145    //!
146    //! Then, add a build script at `build.rs` to build the Scheme source file
147    //! into bytecode.
148    //!
149    //! ```rust no_run
150    //! use stak_build::{build_r7rs, BuildError};
151    //!
152    //! fn main() -> Result<(), BuildError> {
153    //!     build_r7rs()
154    //! }
155    //! ```
156    //!
157    //! Finally, you can include the Scheme script into a Rust program using
158    //! [`include_module`][super::include_module] macro and run the script.
159    //!
160    //! ```rust
161    //! use core::error::Error;
162    //! use stak::{
163    //!     device::StdioDevice,
164    //!     file::VoidFileSystem,
165    //!     include_module,
166    //!     process_context::VoidProcessContext,
167    //!     module::Module,
168    //!     r7rs::{SmallError, SmallPrimitiveSet},
169    //!     time::VoidClock,
170    //!     vm::Vm,
171    //! };
172    //!
173    //! const HEAP_SIZE: usize = 1 << 16;
174    //!
175    //! fn main() -> Result<(), Box<dyn Error>> {
176    //!     // Include and run a Scheme script in the bytecode format built by the build script above.
177    //!     run(&include_module!("hello.scm").bytecode())?;
178    //!
179    //!     Ok(())
180    //! }
181    //!
182    //! fn run(bytecode: &[u8]) -> Result<(), SmallError> {
183    //!     // Prepare a heap memory of a virtual machine.
184    //!     let mut heap = [Default::default(); HEAP_SIZE];
185    //!     // Create a virtual machine with its heap memory primitive procedures.
186    //!     let mut vm = Vm::new(
187    //!         &mut heap,
188    //!         SmallPrimitiveSet::new(
189    //!             // Attach standard input, output, and error of this process to a virtual machine.
190    //!             StdioDevice::new(),
191    //!             // Use void system interfaces for security because we don't need them for this example.
192    //!             VoidFileSystem::new(),
193    //!             VoidProcessContext::new(),
194    //!             VoidClock::new(),
195    //!         ),
196    //!     )?;
197    //!
198    //!     // Run bytecode on a virtual machine.
199    //!     vm.run(bytecode.iter().copied())
200    //! }
201    //! ```
202
203    pub use stak_vm::*;
204}
205
206pub use stak_macro::include_module;