forked from M-Labs/artiq
Rust: implement sending for all RPC types.
This commit is contained in:
parent
4cfc4e89b9
commit
5a630067cb
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
use std::string::String;
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
// FIXME: replace these with byteorder core io traits once those are in
|
// FIXME: replace these with byteorder core io traits once those are in
|
||||||
|
@ -63,3 +64,16 @@ pub fn write_bytes(writer: &mut Write, value: &[u8]) -> io::Result<()> {
|
||||||
try!(write_u32(writer, value.len() as u32));
|
try!(write_u32(writer, value.len() as u32));
|
||||||
writer.write_all(value)
|
writer.write_all(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_string(reader: &mut Read) -> io::Result<String> {
|
||||||
|
let mut bytes = try!(read_bytes(reader));
|
||||||
|
let len = bytes.len() - 1; // length without trailing \0
|
||||||
|
bytes.resize(len, 0); // FIXME: don't send \0 in the first place
|
||||||
|
String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> {
|
||||||
|
try!(write_u32(writer, (value.len() + 1) as u32));
|
||||||
|
try!(writer.write_all(value.as_bytes()));
|
||||||
|
write_u8(writer, 0)
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use proto::{write_u8, write_bytes};
|
use proto::*;
|
||||||
use self::tag::{Tag, TagIterator, split_tag};
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
fn recv_value(reader: &mut Read, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
fn recv_value(reader: &mut Read, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
||||||
|
@ -19,10 +19,88 @@ pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *const ()) -> io::
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
pub unsafe fn from_c_str<'a>(ptr: *const u8) -> &'a str {
|
||||||
|
use core::{str, slice};
|
||||||
|
extern { fn strlen(ptr: *const u8) -> usize; }
|
||||||
|
str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, strlen(ptr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
||||||
|
macro_rules! consume_value {
|
||||||
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
|
let ptr = (*data) as *const $ty;
|
||||||
|
*data = ptr.offset(1) as *const ();
|
||||||
|
(|$ptr: *const $ty| $map)(ptr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write_u8(writer, tag.as_u8()));
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => write_u8(writer, b'n'),
|
Tag::None => Ok(()),
|
||||||
_ => unreachable!()
|
Tag::Bool => {
|
||||||
|
consume_value!(u8, |ptr|
|
||||||
|
write_u8(writer, *ptr))
|
||||||
|
}
|
||||||
|
Tag::Int32 => {
|
||||||
|
consume_value!(u32, |ptr|
|
||||||
|
write_u32(writer, *ptr))
|
||||||
|
}
|
||||||
|
Tag::Int64 => {
|
||||||
|
consume_value!(u64, |ptr|
|
||||||
|
write_u64(writer, *ptr))
|
||||||
|
}
|
||||||
|
Tag::Float64 => {
|
||||||
|
consume_value!(u64, |ptr|
|
||||||
|
write_u64(writer, *ptr))
|
||||||
|
}
|
||||||
|
Tag::String => {
|
||||||
|
consume_value!(*const u8, |ptr|
|
||||||
|
write_string(writer, from_c_str(*ptr)))
|
||||||
|
}
|
||||||
|
Tag::Tuple(it, arity) => {
|
||||||
|
let mut it = it.clone();
|
||||||
|
try!(write_u8(writer, arity));
|
||||||
|
for _ in 0..arity {
|
||||||
|
let tag = it.next().expect("truncated tag");
|
||||||
|
try!(send_value(writer, tag, data))
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Tag::List(it) | Tag::Array(it) => {
|
||||||
|
struct List { length: u32, elements: *const () };
|
||||||
|
consume_value!(List, |ptr| {
|
||||||
|
try!(write_u32(writer, (*ptr).length));
|
||||||
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
let mut data = (*ptr).elements;
|
||||||
|
for _ in 0..(*ptr).length as usize {
|
||||||
|
try!(send_value(writer, tag, &mut data));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Tag::Range(it) => {
|
||||||
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
try!(send_value(writer, tag, data));
|
||||||
|
try!(send_value(writer, tag, data));
|
||||||
|
try!(send_value(writer, tag, data));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Tag::Keyword(it) => {
|
||||||
|
struct Keyword { name: *const u8, contents: () };
|
||||||
|
consume_value!(Keyword, |ptr| {
|
||||||
|
try!(write_string(writer, from_c_str((*ptr).name)));
|
||||||
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
let mut data = &(*ptr).contents as *const ();
|
||||||
|
send_value(writer, tag, &mut data)
|
||||||
|
})
|
||||||
|
// Tag::Keyword never appears in composite types, so we don't have
|
||||||
|
// to accurately advance data.
|
||||||
|
}
|
||||||
|
Tag::Object => {
|
||||||
|
struct Object { id: u32 };
|
||||||
|
consume_value!(*const Object, |ptr|
|
||||||
|
write_u32(writer, (**ptr).id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +115,7 @@ pub fn send_args(writer: &mut Write, tag_bytes: &[u8],
|
||||||
for index in 0.. {
|
for index in 0.. {
|
||||||
if let Some(arg_tag) = args_it.next() {
|
if let Some(arg_tag) = args_it.next() {
|
||||||
let mut data = unsafe { *data.offset(index) };
|
let mut data = unsafe { *data.offset(index) };
|
||||||
try!(send_value(writer, arg_tag, &mut data));
|
try!(unsafe { send_value(writer, arg_tag, &mut data) });
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -61,7 +139,7 @@ mod tag {
|
||||||
(arg_tags_bytes, return_tag_bytes)
|
(arg_tags_bytes, return_tag_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Tag<'a> {
|
pub enum Tag<'a> {
|
||||||
None,
|
None,
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -77,6 +155,25 @@ mod tag {
|
||||||
Object
|
Object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Tag<'a> {
|
||||||
|
pub fn as_u8(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Tag::None => b'n',
|
||||||
|
Tag::Bool => b'b',
|
||||||
|
Tag::Int32 => b'i',
|
||||||
|
Tag::Int64 => b'I',
|
||||||
|
Tag::Float64 => b'f',
|
||||||
|
Tag::String => b's',
|
||||||
|
Tag::Tuple(_, _) => b't',
|
||||||
|
Tag::List(_) => b'l',
|
||||||
|
Tag::Array(_) => b'a',
|
||||||
|
Tag::Range(_) => b'r',
|
||||||
|
Tag::Keyword(_) => b'k',
|
||||||
|
Tag::Object => b'O',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TagIterator<'a> {
|
pub struct TagIterator<'a> {
|
||||||
data: &'a [u8]
|
data: &'a [u8]
|
||||||
|
@ -104,23 +201,23 @@ mod tag {
|
||||||
b't' => {
|
b't' => {
|
||||||
let count = self.data[0];
|
let count = self.data[0];
|
||||||
self.data = &self.data[1..];
|
self.data = &self.data[1..];
|
||||||
Tag::Tuple(self.skip(count), count)
|
Tag::Tuple(self.sub(count), count)
|
||||||
}
|
}
|
||||||
b'l' => Tag::List(self.skip(1)),
|
b'l' => Tag::List(self.sub(1)),
|
||||||
b'a' => Tag::Array(self.skip(1)),
|
b'a' => Tag::Array(self.sub(1)),
|
||||||
b'r' => Tag::Range(self.skip(1)),
|
b'r' => Tag::Range(self.sub(1)),
|
||||||
b'k' => Tag::Keyword(self.skip(1)),
|
b'k' => Tag::Keyword(self.sub(1)),
|
||||||
b'O' => Tag::Object,
|
b'O' => Tag::Object,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(&mut self, count: u8) -> TagIterator<'a> {
|
fn sub(&mut self, count: u8) -> TagIterator<'a> {
|
||||||
let origin = self.clone();
|
let data = self.data;
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
self.next().expect("truncated tag");
|
self.next().expect("truncated tag");
|
||||||
}
|
}
|
||||||
origin
|
TagIterator { data: &data[..(data.len() - self.data.len())] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,10 +247,7 @@ mod tag {
|
||||||
try!(write!(f, "String")),
|
try!(write!(f, "String")),
|
||||||
Tag::Tuple(it, cnt) => {
|
Tag::Tuple(it, cnt) => {
|
||||||
try!(write!(f, "Tuple("));
|
try!(write!(f, "Tuple("));
|
||||||
for i in 0..cnt {
|
try!(it.fmt(f));
|
||||||
try!(it.fmt(f));
|
|
||||||
if i != cnt - 1 { try!(write!(f, ", ")) }
|
|
||||||
}
|
|
||||||
try!(write!(f, ")"))
|
try!(write!(f, ")"))
|
||||||
}
|
}
|
||||||
Tag::List(it) => {
|
Tag::List(it) => {
|
||||||
|
|
|
@ -2,17 +2,6 @@ use std::prelude::v1::*;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
|
|
||||||
fn read_string(reader: &mut Read) -> io::Result<String> {
|
|
||||||
let mut bytes = try!(read_bytes(reader));
|
|
||||||
let len = bytes.len() - 1; // length without trailing \0
|
|
||||||
bytes.resize(len, 0); // FIXME: don't send \0 in the first place
|
|
||||||
String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_string(writer: &mut Write, value: &str) -> io::Result<()> {
|
|
||||||
write_bytes(writer, value.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_sync(reader: &mut Read) -> io::Result<()> {
|
fn read_sync(reader: &mut Read) -> io::Result<()> {
|
||||||
let mut sync = [0; 4];
|
let mut sync = [0; 4];
|
||||||
for i in 0.. {
|
for i in 0.. {
|
||||||
|
|
Loading…
Reference in New Issue