]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/wasm/mod.rs
Auto merge of #54813 - petrochenkov:uilocale, r=alexcrichton
[rust.git] / src / libstd / sys / wasm / mod.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! System bindings for the wasm/web platform
12 //!
13 //! This module contains the facade (aka platform-specific) implementations of
14 //! OS level functionality for wasm. Note that this wasm is *not* the emscripten
15 //! wasm, so we have no runtime here.
16 //!
17 //! This is all super highly experimental and not actually intended for
18 //! wide/production use yet, it's still all in the experimental category. This
19 //! will likely change over time.
20 //!
21 //! Currently all functions here are basically stubs that immediately return
22 //! errors. The hope is that with a portability lint we can turn actually just
23 //! remove all this and just omit parts of the standard library if we're
24 //! compiling for wasm. That way it's a compile time error for something that's
25 //! guaranteed to be a runtime error!
26
27 use io;
28 use os::raw::c_char;
29 use ptr;
30 use sys::os_str::Buf;
31 use sys_common::{AsInner, FromInner};
32 use ffi::{OsString, OsStr};
33 use time::Duration;
34
35 pub mod args;
36 #[cfg(feature = "backtrace")]
37 pub mod backtrace;
38 pub mod cmath;
39 pub mod env;
40 pub mod fs;
41 pub mod memchr;
42 pub mod net;
43 pub mod os;
44 pub mod os_str;
45 pub mod path;
46 pub mod pipe;
47 pub mod process;
48 pub mod stack_overflow;
49 pub mod thread;
50 pub mod time;
51 pub mod stdio;
52
53 cfg_if! {
54     if #[cfg(target_feature = "atomics")] {
55         #[path = "condvar_atomics.rs"]
56         pub mod condvar;
57         #[path = "mutex_atomics.rs"]
58         pub mod mutex;
59         #[path = "rwlock_atomics.rs"]
60         pub mod rwlock;
61         #[path = "thread_local_atomics.rs"]
62         pub mod thread_local;
63     } else {
64         pub mod condvar;
65         pub mod mutex;
66         pub mod rwlock;
67         pub mod thread_local;
68     }
69 }
70
71 #[cfg(not(test))]
72 pub fn init() {
73 }
74
75 pub fn unsupported<T>() -> io::Result<T> {
76     Err(unsupported_err())
77 }
78
79 pub fn unsupported_err() -> io::Error {
80     io::Error::new(io::ErrorKind::Other,
81                    "operation not supported on wasm yet")
82 }
83
84 pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
85     io::ErrorKind::Other
86 }
87
88 // This enum is used as the storage for a bunch of types which can't actually
89 // exist.
90 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
91 pub enum Void {}
92
93 pub unsafe fn strlen(mut s: *const c_char) -> usize {
94     let mut n = 0;
95     while *s != 0 {
96         n += 1;
97         s = s.offset(1);
98     }
99     return n
100 }
101
102 pub unsafe fn abort_internal() -> ! {
103     ExitSysCall::perform(1)
104 }
105
106 // We don't have randomness yet, but I totally used a random number generator to
107 // generate these numbers.
108 //
109 // More seriously though this is just for DOS protection in hash maps. It's ok
110 // if we don't do that on wasm just yet.
111 pub fn hashmap_random_keys() -> (u64, u64) {
112     (1, 2)
113 }
114
115 // Implement a minimal set of system calls to enable basic IO
116 pub enum SysCallIndex {
117     Read = 0,
118     Write = 1,
119     Exit = 2,
120     Args = 3,
121     GetEnv = 4,
122     SetEnv = 5,
123     Time = 6,
124 }
125
126 #[repr(C)]
127 pub struct ReadSysCall {
128     fd: usize,
129     ptr: *mut u8,
130     len: usize,
131     result: usize,
132 }
133
134 impl ReadSysCall {
135     pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
136         let mut call_record = ReadSysCall {
137             fd,
138             len: buffer.len(),
139             ptr: buffer.as_mut_ptr(),
140             result: 0
141         };
142         if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
143             call_record.result
144         } else {
145             0
146         }
147     }
148 }
149
150 #[repr(C)]
151 pub struct WriteSysCall {
152     fd: usize,
153     ptr: *const u8,
154     len: usize,
155 }
156
157 impl WriteSysCall {
158     pub fn perform(fd: usize, buffer: &[u8]) {
159         let mut call_record = WriteSysCall {
160             fd,
161             len: buffer.len(),
162             ptr: buffer.as_ptr()
163         };
164         unsafe { syscall(SysCallIndex::Write, &mut call_record); }
165     }
166 }
167
168 #[repr(C)]
169 pub struct ExitSysCall {
170     code: usize,
171 }
172
173 impl ExitSysCall {
174     pub fn perform(code: usize) -> ! {
175         let mut call_record = ExitSysCall {
176             code
177         };
178         unsafe {
179             syscall(SysCallIndex::Exit, &mut call_record);
180             ::intrinsics::abort();
181         }
182     }
183 }
184
185 fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
186     -> Result<Vec<u8>, E>
187 {
188     let mut buffer = vec![0; estimate];
189     loop {
190         let result = f(&mut buffer)?;
191         if result <= buffer.len() {
192             buffer.truncate(result);
193             break;
194         }
195         buffer.resize(result, 0);
196     }
197     Ok(buffer)
198 }
199
200 #[repr(C)]
201 pub struct ArgsSysCall {
202     ptr: *mut u8,
203     len: usize,
204     result: usize
205 }
206
207 impl ArgsSysCall {
208     pub fn perform() -> Vec<OsString> {
209         receive_buffer(1024, |buffer| -> Result<usize, !> {
210             let mut call_record = ArgsSysCall {
211                 len: buffer.len(),
212                 ptr: buffer.as_mut_ptr(),
213                 result: 0
214             };
215             if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
216                 Ok(call_record.result)
217             } else {
218                 Ok(0)
219             }
220         })
221             .unwrap()
222             .split(|b| *b == 0)
223             .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
224             .collect()
225     }
226 }
227
228 #[repr(C)]
229 pub struct GetEnvSysCall {
230     key_ptr: *const u8,
231     key_len: usize,
232     value_ptr: *mut u8,
233     value_len: usize,
234     result: usize
235 }
236
237 impl GetEnvSysCall {
238     pub fn perform(key: &OsStr) -> Option<OsString> {
239         let key_buf = &AsInner::as_inner(key).inner;
240         receive_buffer(64, |buffer| {
241             let mut call_record = GetEnvSysCall {
242                 key_len: key_buf.len(),
243                 key_ptr: key_buf.as_ptr(),
244                 value_len: buffer.len(),
245                 value_ptr: buffer.as_mut_ptr(),
246                 result: !0usize
247             };
248             if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
249                 if call_record.result == !0usize {
250                     Err(())
251                 } else {
252                     Ok(call_record.result)
253                 }
254             } else {
255                 Err(())
256             }
257         }).ok().map(|s| {
258             FromInner::from_inner(Buf { inner: s })
259         })
260     }
261 }
262
263 #[repr(C)]
264 pub struct SetEnvSysCall {
265     key_ptr: *const u8,
266     key_len: usize,
267     value_ptr: *const u8,
268     value_len: usize
269 }
270
271 impl SetEnvSysCall {
272     pub fn perform(key: &OsStr, value: Option<&OsStr>) {
273         let key_buf = &AsInner::as_inner(key).inner;
274         let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
275         let mut call_record = SetEnvSysCall {
276             key_len: key_buf.len(),
277             key_ptr: key_buf.as_ptr(),
278             value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
279             value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
280         };
281         unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
282     }
283 }
284
285 pub enum TimeClock {
286     Monotonic = 0,
287     System = 1,
288 }
289
290 #[repr(C)]
291 pub struct TimeSysCall {
292     clock: usize,
293     secs_hi: usize,
294     secs_lo: usize,
295     nanos: usize
296 }
297
298 impl TimeSysCall {
299     pub fn perform(clock: TimeClock) -> Duration {
300         let mut call_record = TimeSysCall {
301             clock: clock as usize,
302             secs_hi: 0,
303             secs_lo: 0,
304             nanos: 0
305         };
306         if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
307             Duration::new(
308                 ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
309                 call_record.nanos as u32
310             )
311         } else {
312             panic!("Time system call is not implemented by WebAssembly host");
313         }
314     }
315 }
316
317 unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
318     #[cfg(feature = "wasm_syscall")]
319     extern {
320         #[no_mangle]
321         fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
322     }
323
324     #[cfg(not(feature = "wasm_syscall"))]
325     unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
326
327     rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
328 }