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;