Skip to content

Commit ca815ba

Browse files
committed
Factored out unix dependency
1 parent 63c8308 commit ca815ba

File tree

4 files changed

+74
-23
lines changed

4 files changed

+74
-23
lines changed

vm/src/exceptions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub struct ExceptionZoo {
9292
pub module_not_found_error: PyObjectRef,
9393
pub name_error: PyObjectRef,
9494
pub not_implemented_error: PyObjectRef,
95+
pub os_error: PyObjectRef,
9596
pub permission_error: PyObjectRef,
9697
pub runtime_error: PyObjectRef,
9798
pub stop_iteration: PyObjectRef,
@@ -135,6 +136,7 @@ impl ExceptionZoo {
135136
let syntax_error = create_type("SyntaxError", &type_type, &exception_type, &dict_type);
136137
let type_error = create_type("TypeError", &type_type, &exception_type, &dict_type);
137138
let value_error = create_type("ValueError", &type_type, &exception_type, &dict_type);
139+
let os_error = create_type("OSError", &type_type, &exception_type.clone(), &dict_type);
138140

139141
let file_not_found_error =
140142
create_type("FileNotFoundError", &type_type, &import_error, &dict_type);
@@ -167,6 +169,7 @@ impl ExceptionZoo {
167169
syntax_error,
168170
type_error,
169171
value_error,
172+
os_error,
170173
}
171174
}
172175
}

vm/src/stdlib/io.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
* I/O core tools.
33
*/
44

5+
//library imports
56
use std::collections::HashSet;
6-
7-
use std::io::prelude::*;
8-
use std::os::unix::io::{FromRawFd, IntoRawFd};
9-
107
use std::fs::File;
8+
use std::io::prelude::*;
119
use std::io::BufReader;
1210

11+
//3rd party imports
12+
use num_bigint::ToBigInt;
13+
use num_traits::ToPrimitive;
14+
15+
//custom imports
1316
use super::super::obj::objbytes;
1417
use super::super::obj::objint;
1518
use super::super::obj::objstr;
1619
use super::super::obj::objtype;
1720
use super::os;
1821

19-
use num_bigint::ToBigInt;
20-
use num_traits::ToPrimitive;
21-
2222
use super::super::pyobject::{
2323
AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef,
2424
PyResult, TypeProtocol,
@@ -117,6 +117,9 @@ fn file_io_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
117117

118118
vm.ctx.set_attr(&file_io, "name", name.clone());
119119
vm.ctx.set_attr(&file_io, "fileno", file_no);
120+
vm.ctx.set_attr(&file_io, "closefd", vm.new_bool(false));
121+
vm.ctx.set_attr(&file_io, "closed", vm.new_bool(false));
122+
120123
Ok(vm.get_none())
121124
}
122125
None => Err(vm.new_type_error(format!("invalid mode {}", rust_mode))),
@@ -164,10 +167,8 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
164167
let file_no = file_io.get_attr("fileno").unwrap();
165168
let raw_fd = objint::get_value(&file_no).to_i32().unwrap();
166169

167-
//unsafe block - creates file handle from the UNIX file descriptor
168-
//raw_fd is supported on UNIX only. This will need to be extended
169-
//to support windows - i.e. raw file_handles
170-
let handle = unsafe { File::from_raw_fd(raw_fd) };
170+
//extract unix file descriptor.
171+
let handle = os::rust_file(raw_fd);
171172

172173
let mut f = handle.take(length);
173174
match obj.borrow_mut().payload {
@@ -182,9 +183,9 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
182183
_ => {}
183184
};
184185

185-
let new_handle = f.into_inner().into_raw_fd().to_bigint();
186+
let updated = os::raw_file_number(f.into_inner()).to_bigint();
186187
vm.ctx
187-
.set_attr(&file_io, "fileno", vm.ctx.new_int(new_handle.unwrap()));
188+
.set_attr(&file_io, "fileno", vm.ctx.new_int(updated.unwrap()));
188189
Ok(vm.get_none())
189190
}
190191

@@ -201,16 +202,16 @@ fn file_io_write(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
201202
//unsafe block - creates file handle from the UNIX file descriptor
202203
//raw_fd is supported on UNIX only. This will need to be extended
203204
//to support windows - i.e. raw file_handles
204-
let mut handle = unsafe { File::from_raw_fd(raw_fd) };
205+
let mut handle = os::rust_file(raw_fd);
205206

206207
match obj.borrow_mut().payload {
207208
PyObjectPayload::Bytes { ref mut value } => {
208209
match handle.write(&value[..]) {
209210
Ok(len) => {
210211
//reset raw fd on the FileIO object
211-
let new_handle = handle.into_raw_fd().to_bigint();
212+
let updated = os::raw_file_number(handle).to_bigint();
212213
vm.ctx
213-
.set_attr(&file_io, "fileno", vm.ctx.new_int(new_handle.unwrap()));
214+
.set_attr(&file_io, "fileno", vm.ctx.new_int(updated.unwrap()));
214215

215216
//return number of bytes written
216217
Ok(vm.ctx.new_int(len.to_bigint().unwrap()))
@@ -279,7 +280,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
279280

280281
let mut raw_modes = HashSet::new();
281282

282-
// Add some books.
283+
//add raw modes
283284
raw_modes.insert("a".to_string());
284285
raw_modes.insert("r".to_string());
285286
raw_modes.insert("x".to_string());

vm/src/stdlib/os.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,61 @@
1+
//library imports
2+
use std::fs::File;
13
use std::fs::OpenOptions;
24
use std::io::ErrorKind;
3-
use std::os::unix::io::IntoRawFd;
45

6+
//3rd party imports
57
use num_bigint::ToBigInt;
68
use num_traits::cast::ToPrimitive;
79

10+
//custom imports
811
use super::super::obj::objint;
912
use super::super::obj::objstr;
1013
use super::super::obj::objtype;
1114

1215
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
13-
1416
use super::super::vm::VirtualMachine;
1517

18+
#[cfg(target_family = "unix")]
19+
pub fn raw_file_number(handle: File) -> i32 {
20+
use std::os::unix::io::IntoRawFd;
21+
22+
handle.into_raw_fd()
23+
}
24+
25+
#[cfg(target_family = "unix")]
26+
pub fn rust_file(raw_fileno: i32) -> File {
27+
use std::os::unix::io::FromRawFd;
28+
29+
unsafe { File::from_raw_fd(raw_fileno) }
30+
}
31+
32+
#[cfg(target_family = "windows")]
33+
pub fn rust_file(handle: File) -> i32 {
34+
use std::os::windows::io::IntoRawHandle;
35+
36+
handle.into_raw_handle()
37+
}
38+
39+
#[cfg(target_family = "windows")]
40+
pub fn rust_file(raw_fileno: i32) -> File {
41+
use std::os::unix::io::FromRawHandle;
42+
43+
unsafe { File::from_raw_handle(raw_fileno) }
44+
}
45+
46+
pub fn os_close(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
47+
arg_check!(vm, args, required = [(fileno, Some(vm.ctx.int_type()))]);
48+
49+
let raw_fileno = objint::get_value(&fileno);
50+
51+
//The File type automatically closes when it goes out of scope.
52+
//To enable us to close these file desciptors (and hence prevent leaks)
53+
//we seek to create the relevant File and simply let it pass out of scope!
54+
rust_file(raw_fileno.to_i32().unwrap());
55+
56+
Ok(vm.get_none())
57+
}
58+
1659
pub fn os_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
1760
arg_check!(
1861
vm,
@@ -43,11 +86,8 @@ pub fn os_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4386
_ => vm.new_value_error("Unhandled file IO error".to_string()),
4487
})?;
4588

46-
//raw_fd is supported on UNIX only. This will need to be extended
47-
//to support windows - i.e. raw file_handles
4889
Ok(vm.ctx.new_int(
49-
handle
50-
.into_raw_fd()
90+
raw_file_number(handle)
5191
.to_bigint()
5292
.expect("Invalid file descriptor"),
5393
))
@@ -56,6 +96,8 @@ pub fn os_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5696
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
5797
let py_mod = ctx.new_module(&"io".to_string(), ctx.new_scope(None));
5898
ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(os_open));
99+
ctx.set_attr(&py_mod, "close", ctx.new_rustfunc(os_close));
100+
59101
ctx.set_attr(&py_mod, "O_RDONLY", ctx.new_int(0.to_bigint().unwrap()));
60102
ctx.set_attr(&py_mod, "O_WRONLY", ctx.new_int(1.to_bigint().unwrap()));
61103
ctx.set_attr(&py_mod, "O_RDWR", ctx.new_int(2.to_bigint().unwrap()));

vm/src/vm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ impl VirtualMachine {
100100
self.new_exception(type_error, msg)
101101
}
102102

103+
pub fn new_os_error(&mut self, msg: String) -> PyObjectRef {
104+
let os_error = self.ctx.exceptions.os_error.clone();
105+
self.new_exception(os_error, msg)
106+
}
107+
103108
/// Create a new python ValueError object. Useful for raising errors from
104109
/// python functions implemented in rust.
105110
pub fn new_value_error(&mut self, msg: String) -> PyObjectRef {

0 commit comments

Comments
 (0)