@@ -10,7 +10,6 @@ pub mod runtime;
1010pub mod test_utils;
1111pub mod tools;
1212
13- use std:: any:: Any ;
1413use std:: path:: { Path , PathBuf } ;
1514
1615use anyhow:: Result ;
@@ -30,13 +29,13 @@ pub use tools::{ArgType, ToolRegistry, ToolSchema};
3029#[ cfg( windows) ]
3130pub const DEFAULT_HEAP_SIZE : u64 = 400 * 1024 * 1024 ;
3231#[ cfg( not( windows) ) ]
33- pub const DEFAULT_HEAP_SIZE : u64 = 200 * 1024 * 1024 ;
32+ pub const DEFAULT_HEAP_SIZE : u64 = 25 * 1024 * 1024 ;
3433
3534/// Default guest stack / scratch size in bytes (platform-dependent).
3635#[ cfg( windows) ]
3736pub const DEFAULT_STACK_SIZE : u64 = 200 * 1024 * 1024 ;
3837#[ cfg( not( windows) ) ]
39- pub const DEFAULT_STACK_SIZE : u64 = 100 * 1024 * 1024 ;
38+ pub const DEFAULT_STACK_SIZE : u64 = 35 * 1024 * 1024 ;
4039
4140/// Configuration for building a sandbox guest.
4241#[ derive( Debug , Clone ) ]
@@ -75,42 +74,31 @@ pub struct ExecutionResult {
7574// Snapshot
7675// ---------------------------------------------------------------------------
7776
78- #[ derive( Clone ) ]
79- pub struct Snapshot {
77+ pub struct Snapshot < T > {
8078 kind : & ' static str ,
81- runtime : std:: sync:: Arc < dyn Any + Send + Sync > ,
79+ snapshot : std:: sync:: Arc < T > ,
8280}
8381
84- impl Snapshot {
82+ impl < T > Clone for Snapshot < T > {
83+ fn clone ( & self ) -> Self {
84+ Self {
85+ kind : self . kind ,
86+ snapshot : self . snapshot . clone ( ) ,
87+ }
88+ }
89+ }
90+
91+ impl < T > Snapshot < T > {
8592 pub fn kind ( & self ) -> & ' static str {
8693 self . kind
8794 }
8895
89- pub fn new < T > ( kind : & ' static str , runtime : std:: sync:: Arc < T > ) -> Self
90- where
91- T : Any + Send + Sync + ' static ,
92- {
93- Self { kind, runtime }
96+ pub fn new ( kind : & ' static str , snapshot : std:: sync:: Arc < T > ) -> Self {
97+ Self { kind, snapshot }
9498 }
9599
96- pub fn restore < T > (
97- & self ,
98- restore_runtime : impl FnOnce ( std:: sync:: Arc < T > ) -> Result < ( ) > ,
99- fs : & std:: sync:: Arc < std:: sync:: Mutex < CapFs > > ,
100- ) -> Result < ( ) >
101- where
102- T : Any + Send + Sync + ' static ,
103- {
104- let runtime = self
105- . runtime
106- . clone ( )
107- . downcast :: < T > ( )
108- . map_err ( |_| anyhow:: anyhow!( "snapshot type mismatch (kind: {})" , self . kind) ) ?;
109- restore_runtime ( runtime) ?;
110- fs. lock ( )
111- . map_err ( |_| anyhow:: anyhow!( "filesystem mutex poisoned during snapshot restore" ) ) ?
112- . clear_output_files ( ) ;
113- Ok ( ( ) )
100+ pub fn snapshot ( & self ) -> & std:: sync:: Arc < T > {
101+ & self . snapshot
114102 }
115103}
116104
@@ -119,48 +107,50 @@ impl Snapshot {
119107// ---------------------------------------------------------------------------
120108
121109pub trait Guest : Sized {
110+ type Sandbox : GuestSandbox ;
122111 fn build (
123112 self ,
124113 config : SandboxConfig ,
125114 tools : ToolRegistry ,
126115 network : std:: sync:: Arc < std:: sync:: Mutex < NetworkPermissions > > ,
127116 fs : std:: sync:: Arc < std:: sync:: Mutex < CapFs > > ,
128- ) -> Result < Box < dyn GuestSandbox > > ;
117+ ) -> Result < Self :: Sandbox > ;
129118}
130119
131120pub trait GuestSandbox : Send {
121+ type SnapshotData : Send + Sync + ' static ;
132122 /// Execute guest code.
133123 ///
134124 /// Output files under `/output` are wiped before each execution.
135125 /// Input files are read-only and managed by the host.
136126 fn run ( & mut self , code : & str ) -> Result < ExecutionResult > ;
137127 /// Capture a snapshot of the guest runtime state.
138- fn snapshot ( & mut self ) -> Result < Snapshot > ;
128+ fn snapshot ( & mut self ) -> Result < Snapshot < Self :: SnapshotData > > ;
139129 /// Restore a previously captured guest runtime state.
140- fn restore ( & mut self , snapshot : & Snapshot ) -> Result < ( ) > ;
130+ fn restore ( & mut self , snapshot : & Snapshot < Self :: SnapshotData > ) -> Result < ( ) > ;
141131}
142132
143133// ---------------------------------------------------------------------------
144134// Sandbox
145135// ---------------------------------------------------------------------------
146136
147- pub struct Sandbox {
148- inner : Box < dyn GuestSandbox > ,
137+ pub struct Sandbox < G : Guest > {
138+ inner : G :: Sandbox ,
149139 network : std:: sync:: Arc < std:: sync:: Mutex < NetworkPermissions > > ,
150140 fs : std:: sync:: Arc < std:: sync:: Mutex < CapFs > > ,
151141}
152142
153- impl Sandbox {
143+ impl < G : Guest > Sandbox < G > {
154144 /// Create a sandbox without filesystem access.
155- pub fn new < G : Guest > ( guest : G , config : SandboxConfig , tools : ToolRegistry ) -> Result < Self > {
145+ pub fn new ( guest : G , config : SandboxConfig , tools : ToolRegistry ) -> Result < Self > {
156146 let network = std:: sync:: Arc :: new ( std:: sync:: Mutex :: new ( NetworkPermissions :: new ( ) ) ) ;
157147 let fs = std:: sync:: Arc :: new ( std:: sync:: Mutex :: new ( CapFs :: new ( ) ) ) ;
158148 let inner = guest. build ( config, tools, network. clone ( ) , fs. clone ( ) ) ?;
159149 Ok ( Self { inner, network, fs } )
160150 }
161151
162152 /// Create a sandbox with a read-only input directory.
163- pub fn with_input < G : Guest > (
153+ pub fn with_input (
164154 guest : G ,
165155 config : SandboxConfig ,
166156 tools : ToolRegistry ,
@@ -173,10 +163,6 @@ impl Sandbox {
173163 Ok ( Self { inner, network, fs } )
174164 }
175165
176- pub fn builder ( ) -> SandboxBuilder < NoGuest > {
177- SandboxBuilder :: default ( )
178- }
179-
180166 /// Execute guest code.
181167 ///
182168 /// Output files under `/output` are cleared before each run. Input files
@@ -185,12 +171,17 @@ impl Sandbox {
185171 self . inner . run ( code)
186172 }
187173
188- pub fn snapshot ( & mut self ) -> Result < Snapshot > {
174+ pub fn snapshot ( & mut self ) -> Result < Snapshot < < G :: Sandbox as GuestSandbox > :: SnapshotData > > {
189175 self . inner . snapshot ( )
190176 }
191177
192- pub fn restore ( & mut self , snapshot : & Snapshot ) -> Result < ( ) > {
193- self . inner . restore ( snapshot)
178+ pub fn restore ( & mut self , snapshot : & Snapshot < <G :: Sandbox as GuestSandbox >:: SnapshotData > ) -> Result < ( ) > {
179+ self . inner . restore ( snapshot) ?;
180+ self . fs
181+ . lock ( )
182+ . map_err ( |_| anyhow:: anyhow!( "filesystem mutex poisoned during snapshot restore" ) ) ?
183+ . clear_output_files ( ) ;
184+ Ok ( ( ) )
194185 }
195186
196187 /// List filenames in the output directory (without reading contents).
@@ -231,7 +222,7 @@ pub struct NoGuest;
231222/// Builder for constructing a [`Sandbox`].
232223///
233224/// ```rust,ignore
234- /// let sandbox = Sandbox::builder ()
225+ /// let sandbox = SandboxBuilder::new ()
235226/// .module_path("guest.aot")
236227/// .output_dir("/tmp/sandbox-out")
237228/// .guest(Wasm)
@@ -246,6 +237,12 @@ pub struct SandboxBuilder<G = NoGuest> {
246237 temp_output : bool ,
247238}
248239
240+ impl SandboxBuilder < NoGuest > {
241+ pub fn new ( ) -> Self {
242+ Self :: default ( )
243+ }
244+ }
245+
249246impl Default for SandboxBuilder < NoGuest > {
250247 fn default ( ) -> Self {
251248 Self {
@@ -336,7 +333,7 @@ impl<G> SandboxBuilder<G>
336333where
337334 G : Guest ,
338335{
339- pub fn build ( self ) -> Result < Sandbox > {
336+ pub fn build ( self ) -> Result < Sandbox < G > > {
340337 let network = std:: sync:: Arc :: new ( std:: sync:: Mutex :: new ( NetworkPermissions :: new ( ) ) ) ;
341338 let mut vfs = CapFs :: new ( ) ;
342339 if let Some ( input_dir) = & self . input_dir {
0 commit comments