diff options
Diffstat (limited to 'src/resources.rs')
-rw-r--r-- | src/resources.rs | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/resources.rs b/src/resources.rs new file mode 100644 index 000000000..940b14d21 --- /dev/null +++ b/src/resources.rs @@ -0,0 +1,126 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. + +// Think of Resources as File Descriptors. They are integers that are allocated +// by the privlaged side of Deno to refer to various resources. The simplest +// example are standard file system files and stdio - but there will be other +// resources added in the future that might not correspond to operating system +// level File Descriptors. To avoid confusion we call them "resources" not "file +// descriptors". This module implements a global resource table. Ops (AKA +// handlers) look up resources by their integer id here. + +use futures; +use futures::Poll; +use std; +use std::collections::HashMap; +use std::io::Error; +use std::io::{Read, Write}; +use std::sync::atomic::AtomicIsize; +use std::sync::atomic::Ordering; +use std::sync::Mutex; +use tokio; +use tokio::io::{AsyncRead, AsyncWrite}; + +pub type ResourceId = i32; // Sometimes referred to RID. + +// These store Deno's file descriptors. These are not necessarily the operating +// system ones. +type ResourceTable = HashMap<ResourceId, Repr>; + +lazy_static! { + // Starts at 3 because stdio is [0-2]. + static ref NEXT_RID: AtomicIsize = AtomicIsize::new(3); + static ref RESOURCE_TABLE: Mutex<ResourceTable> = Mutex::new({ + let mut m = HashMap::new(); + // TODO Load these lazily during lookup? + m.insert(0, Repr::Stdin(tokio::io::stdin())); + m.insert(1, Repr::Stdout(tokio::io::stdout())); + m.insert(2, Repr::Stderr(tokio::io::stderr())); + m + }); +} + +// Internal representation of Resource. +enum Repr { + Stdin(tokio::io::Stdin), + Stdout(tokio::io::Stdout), + Stderr(tokio::io::Stderr), + FsFile(tokio::fs::File), +} + +// Abstract async file interface. +// Ideally in unix, if Resource represents an OS rid, it will be the same. +pub struct Resource { + pub rid: ResourceId, +} + +impl Read for Resource { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> { + unimplemented!(); + } +} + +impl AsyncRead for Resource { + fn poll_read(&mut self, buf: &mut [u8]) -> Poll<usize, Error> { + let mut table = RESOURCE_TABLE.lock().unwrap(); + let maybe_repr = table.get_mut(&self.rid); + match maybe_repr { + None => panic!("bad rid"), + Some(repr) => match repr { + Repr::FsFile(ref mut f) => f.poll_read(buf), + Repr::Stdin(ref mut f) => f.poll_read(buf), + Repr::Stdout(_) | Repr::Stderr(_) => { + panic!("Cannot read from stdout/stderr") + } + }, + } + } +} + +impl Write for Resource { + fn write(&mut self, _buf: &[u8]) -> std::io::Result<usize> { + unimplemented!() + } + + fn flush(&mut self) -> std::io::Result<()> { + unimplemented!() + } +} + +impl AsyncWrite for Resource { + fn poll_write(&mut self, buf: &[u8]) -> Poll<usize, Error> { + let mut table = RESOURCE_TABLE.lock().unwrap(); + let maybe_repr = table.get_mut(&self.rid); + match maybe_repr { + None => panic!("bad rid"), + Some(repr) => match repr { + Repr::FsFile(ref mut f) => f.poll_write(buf), + Repr::Stdout(ref mut f) => f.poll_write(buf), + Repr::Stderr(ref mut f) => f.poll_write(buf), + Repr::Stdin(_) => panic!("Cannot write to stdin"), + }, + } + } + + fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> { + unimplemented!() + } +} + +fn new_rid() -> ResourceId { + let next_rid = NEXT_RID.fetch_add(1, Ordering::SeqCst); + next_rid as ResourceId +} + +pub fn add_fs_file(fs_file: tokio::fs::File) -> Resource { + let rid = new_rid(); + let mut tg = RESOURCE_TABLE.lock().unwrap(); + match tg.insert(rid, Repr::FsFile(fs_file)) { + Some(_) => panic!("There is already a file with that rid"), + None => Resource { rid }, + } +} + +pub fn lookup(rid: ResourceId) -> Option<Resource> { + let table = RESOURCE_TABLE.lock().unwrap(); + table.get(&rid).map(|_| Resource { rid }) +} |