use std::io::Result as IoResult;
use std::io::Error as IoError;
use std::io::Write;
use std::string::ToString;
use serde::de::{Deserialize, Deserializer};
use super::parser::Node;
use self::State as S;
use self::Line as L;
use self::ScalarStyle::{Plain};
use super::parser::Node as N; use super::ast::Tag::{LocalTag, GlobalTag, NonSpecific};
use super::ast::Tag as AstTag;
use super::ast::Ast;
use super::ast::Ast as A;
use super::ast::NullKind::{Explicit, Implicit};
pub type Tag<'a> = &'a str;
pub type Anchor<'a> = &'a str;
#[derive(Clone, Copy)]
enum ScalarStyle {
Auto,
Plain,
SingleQuoted,
DoubleQuoted,
Literal,
Folded,
}
#[derive(Clone, Copy)]
enum Null {
Nothing,
Tilde,
Null,
}
#[derive(Clone, Copy)]
enum State {
New,
MapKey,
MapSimpleKeyValue,
MapValue,
SeqItem,
Fin,
}
#[derive(PartialEq, Eq)]
enum Line {
Start,
AfterIndent, AfterScalar, }
#[derive(Clone, Copy)]
enum Opcode<'a> {
MapStart(Option<Tag<'a>>, Option<Anchor<'a>>),
MapEnd,
SeqStart(Option<Tag<'a>>, Option<Anchor<'a>>),
SeqEnd,
Null(Option<Tag<'a>>, Option<Anchor<'a>>, Null),
Scalar(Option<Tag<'a>>, Option<Anchor<'a>>, ScalarStyle, &'a str),
Comment(&'a str),
Alias(&'a str),
}
struct Context<'a> {
cur_indent: usize,
stream: &'a mut (Write + 'a),
stack: Vec<(State, usize)>,
state: State,
line: Line,
}
fn tag_as_string<'x>(tag: &'x AstTag) -> Option<&'x str> {
return (match *tag {
NonSpecific => None,
LocalTag(ref value) => Some(value),
GlobalTag(_) => unimplemented!(),
}).map(|t| &t[..]);
}
impl<'a> Context<'a> {
pub fn new<'x>(stream: &'x mut Write) -> Context<'x> {
return Context {
cur_indent: 0,
stream: stream,
stack: Vec::new(),
state: S::New,
line: L::Start,
};
}
fn emit_scalar(&mut self, style: ScalarStyle, value: &str)
-> IoResult<()>
{
match style {
ScalarStyle::Auto|ScalarStyle::Plain => {
self.line = L::AfterScalar;
return self.stream.write(&value[..].as_bytes()).map(|_| ());
}
ScalarStyle::SingleQuoted => {
unimplemented!();
}
ScalarStyle::DoubleQuoted => {
unimplemented!();
}
ScalarStyle::Literal => {
unimplemented!();
}
ScalarStyle::Folded => {
unimplemented!();
}
}
}
fn emit_null(&mut self, space:bool, style: Null) -> IoResult<()> {
return match style {
Null::Nothing => {
Ok(0)
}
Null::Tilde =>
self.stream.write(if space { b" ~" } else { b"~" }),
Null::Null =>
self.stream.write(if space { b" null" } else { b"null"}),
}.map(|_| ());
}
fn push_indent(&mut self, state: State, value: usize) {
self.stack.push((state, self.cur_indent));
self.cur_indent += value;
}
fn pop_indent(&mut self) -> State {
let (val, indent) = self.stack.pop().unwrap();
self.cur_indent = indent;
return val;
}
fn ensure_line_start(&mut self) -> IoResult<()> {
match self.line {
L::Start => {
return Ok(());
}
L::AfterScalar | L::AfterIndent => {
self.line = L::Start;
return self.stream.write(b"\n").map(|_| ());
}
}
}
fn ensure_indented(&mut self) -> IoResult<()> {
match self.line {
L::AfterIndent => return Ok(()),
_ => {}
}
self.ensure_line_start()?;
for _ in 0..self.cur_indent {
self.stream.write(b" ")?;
}
return Ok(());
}
pub fn emit_tag_anchor(&mut self, tag: Option<Tag>,
anchor: Option<Tag>, space: bool) -> IoResult<()> {
match tag {
Some(x) => {
self.stream.write(b"!")?;
self.stream.write(x.as_bytes())?;
if space {
self.stream.write(b" ")?;
} else {
self.line = L::Start;
return self.stream.write(b"\n").map(|_| ());
}
}
None => {}
}
match anchor {
Some(_) => {
unimplemented!();
}
None => {}
}
return Ok(());
}
fn emit(&mut self, op: Opcode) -> IoResult<()> {
self.state = match (self.state, op) {
(S::Fin, _) => unreachable!(),
(S::New, Opcode::Scalar(tag, anchor, style, value)) => {
self.emit_tag_anchor(tag, anchor, true)?;
self.emit_scalar(style, value)?;
self.ensure_line_start()?;
S::Fin }
(S::New, Opcode::Null(tag, anchor, style)) => {
self.emit_tag_anchor(tag, anchor, false)?;
self.emit_null(false, style)?;
self.ensure_line_start()?;
S::Fin }
(S::New, Opcode::MapStart(tag, anchor)) => {
self.emit_tag_anchor(tag, anchor, false)?;
if tag.is_some() || anchor.is_some() {
self.ensure_line_start()?;
}
self.push_indent(S::Fin, 0);
S::MapKey }
(S::MapKey, Opcode::Scalar(tag, anchor, style, value)) => {
self.ensure_indented()?;
self.emit_tag_anchor(tag, anchor, true)?;
self.emit_scalar(style, value)?;
S::MapSimpleKeyValue }
(S::MapKey, Opcode::Null(tag, anchor, style)) => {
self.ensure_indented()?;
self.emit_tag_anchor(tag, anchor, false)?;
self.emit_null(false, style)?;
self.ensure_line_start()?;
S::MapKey }
(S::MapSimpleKeyValue, Opcode::Scalar(tag, anchor, style, value))
=> {
self.stream.write(b": ")?;
self.emit_tag_anchor(tag, anchor, true)?;
self.emit_scalar(style, value)?;
S::MapKey }
(S::MapSimpleKeyValue, Opcode::Null(tag, anchor, style)) => {
self.stream.write(b": ")?;
self.emit_tag_anchor(tag, anchor, false)?;
self.emit_null(false, style)?;
self.ensure_line_start()?;
S::MapKey }
(S::MapSimpleKeyValue, Opcode::MapStart(tag, anchor)) => {
self.stream.write(b":")?;
if tag.is_some() || anchor.is_some() {
self.stream.write(b" ")?;
self.emit_tag_anchor(tag, anchor, false)?;
} else {
self.line = L::AfterScalar;
}
self.push_indent(S::MapKey, 2);
S::MapKey }
(S::MapSimpleKeyValue, Opcode::SeqStart(tag, anchor)) => {
self.stream.write(b":")?;
self.line = L::AfterScalar;
self.push_indent(S::MapKey, 0);
S::SeqItem }
(S::MapKey, Opcode::MapEnd) => {
let nstate = self.pop_indent();
match nstate {
S::Fin => self.ensure_line_start()?,
_ => {}
}
nstate }
(S::New, Opcode::SeqStart(tag, anchor)) => {
self.emit_tag_anchor(tag, anchor, false)?;
if tag.is_some() || anchor.is_some() {
self.ensure_line_start()?;
}
self.push_indent(S::Fin, 0);
S::SeqItem }
(S::SeqItem, Opcode::Scalar(tag, anchor, style, value)) => {
self.ensure_indented()?;
self.stream.write(b"- ")?;
self.emit_tag_anchor(tag, anchor, true)?;
self.emit_scalar(style, value)?;
S::SeqItem }
(S::SeqItem, Opcode::MapStart(tag, anchor)) => {
self.emit_tag_anchor(tag, anchor, false)?;
if tag.is_some() || anchor.is_some() {
self.ensure_line_start()?;
}
self.ensure_indented()?;
self.stream.write(b"- ")?;
self.line = L::AfterIndent;
self.push_indent(S::SeqItem, 2);
S::MapKey }
(S::SeqItem, Opcode::SeqEnd) => {
let nstate = self.pop_indent();
match nstate {
S::Fin => self.ensure_line_start()?,
_ => {}
}
nstate }
(_, _) => unimplemented!(),
};
return Ok(());
}
pub fn emit_node(&mut self, node: &Node) -> IoResult<()> {
match node {
&N::Map(tag, anchor, ref map, _) => {
self.emit(Opcode::MapStart(tag.map(|t| &t[1..]),
anchor))?;
for (k, v) in map.iter() {
self.emit_node(k)?;
self.emit_node(v)?;
}
self.emit(Opcode::MapEnd)?;
}
&N::Seq(tag, anchor, ref items, _) => {
self.emit(Opcode::SeqStart(tag.map(|t| &t[1..]),
anchor))?;
for i in items.iter() {
self.emit_node(i)?;
}
self.emit(Opcode::SeqEnd)?;
},
&N::Scalar(ref tag, _anchor, ref value, _) => {
self.emit(Opcode::Scalar(tag.map(|t| &t[1..]),
None, ScalarStyle::Auto, value))?;
}
&N::ImplicitNull(ref tag, ref _anchor, ref _token) => {
self.emit(Opcode::Null(tag.map(|t| &t[1..]),
None, Null::Nothing))?;
}
&N::Alias(name, _, _) => {
self.emit(Opcode::Alias(name))?;
}
}
return Ok(());
}
pub fn emit_ast(&mut self, node: &Ast) -> IoResult<()> {
match node {
&A::Map(_, ref tag, ref map) => {
self.emit(Opcode::MapStart(tag_as_string(tag), None))?;
for (k, v) in map.iter() {
self.emit(Opcode::Scalar(None, None,
ScalarStyle::Auto, k))?;
self.emit_ast(v)?;
}
self.emit(Opcode::MapEnd)?;
}
&A::Seq(_, ref tag, ref items) => {
self.emit(Opcode::SeqStart(tag_as_string(tag), None))?;
for i in items.iter() {
self.emit_ast(i)?;
}
self.emit(Opcode::SeqEnd)?;
},
&A::Scalar(_, ref tag, _, ref value) => {
self.emit(Opcode::Scalar(tag_as_string(tag), None,
ScalarStyle::Auto, value))?;
}
&A::Null(_, ref tag, ref kind) => {
self.emit(Opcode::Null(tag_as_string(tag), None, match *kind {
Explicit => Null::Null,
Implicit => Null::Nothing,
}))?;
}
}
return Ok(());
}
fn to_buffer<'x, T: Encodable, W: Write>(
val: &T, wr: &'x mut W)
{
let mut encoder = Context::new(wr);
val.encode(&mut encoder).unwrap();
}
}
pub fn emit_parse_tree(tree: &Node, stream: &mut Write)
-> IoResult<()>
{
let mut ctx = Context::new(stream);
return ctx.emit_node(tree);
}
pub fn emit_ast(tree: &Ast, stream: &mut Write)
-> IoResult<()>
{
let mut ctx = Context::new(stream);
return ctx.emit_ast(tree);
}
pub fn emit_object<'x, T: Deserialize>(
val: &T, wr: &'x mut Write) -> Result<(), IoError>
{
let mut encoder = Context::new(wr);
val.encode(&mut encoder)
}
impl<'a> Deserializer for Context<'a> {
type Error = IoError;
fn emit_nil(&mut self) -> Result<(), IoError> {
return self.emit(Opcode::Null(None, None, Null::Nothing));
}
fn emit_usize(&mut self, v: usize) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_u64(&mut self, v: u64) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_u32(&mut self, v: u32) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_u16(&mut self, v: u16) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_u8(&mut self, v: u8) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_isize(&mut self, v: isize) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_i64(&mut self, v: i64) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_i32(&mut self, v: i32) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_i16(&mut self, v: i16) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_i8(&mut self, v: i8) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_bool(&mut self, v: bool) -> Result<(), IoError> {
return self.emit(Opcode::Scalar(None, None, Plain,
if v { "true" } else { "false" }));
}
fn emit_f64(&mut self, v: f64) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_f32(&mut self, v: f32) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, Plain, &val));
}
fn emit_char(&mut self, v: char) -> Result<(), IoError> {
let val = v.to_string();
return self.emit(Opcode::Scalar(None, None, ScalarStyle::Auto, &val));
}
fn emit_str(&mut self, v: &str) -> Result<(), IoError> {
return self.emit(Opcode::Scalar(None, None, ScalarStyle::Auto, v));
}
fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), IoError> {
unimplemented!();
}
fn emit_enum_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F)
-> Result<(), IoError>
{
unimplemented!();
}
fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F)
-> Result<(), IoError>
{
unimplemented!();
}
fn emit_enum_struct_variant<F>(&mut self, v_name: &str,
v_id: usize, len: usize, f: F)
-> Result<(), IoError>
{
unimplemented!();
}
fn emit_enum_struct_variant_field<F>(&mut self, f_name: &str, f_idx: usize,
f: F)
-> Result<(), IoError>
{
unimplemented!();
}
fn emit_struct<F>(&mut self, name: &str, len: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
self.emit(Opcode::MapStart(None, None))
.and(f(self))
.and(self.emit(Opcode::MapEnd))
}
fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
self.emit(Opcode::Scalar(None, None, ScalarStyle::Auto, f_name))
.and(f(self))
}
fn emit_tuple<F>(&mut self, len: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_tuple_arg<F>(&mut self, idx: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F)
-> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_option<F>(&mut self, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_option_none(&mut self) -> Result<(), IoError> {
unimplemented!();
}
fn emit_option_some<F>(&mut self, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
self.emit(Opcode::SeqStart(None, None))
.and(f(self))
.and(self.emit(Opcode::SeqEnd))
}
fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
f(self)
}
fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), IoError>
where F: FnOnce(&mut Self) -> Result<(), IoError>
{
unimplemented!();
}
}
#[cfg(test)]
mod test {
use std::str::{from_utf8};
use std::rc::Rc;
use errors::ErrorCollector;
use super::super::parser::parse;
use super::{Null, Opcode};
use super::super::ast::process;
use super::Context;
use super::ScalarStyle;
use {Options};
fn emit_and_compare(list: &[Opcode], output: &str) {
let mut bytes = Vec::new();
{
let mut ctx = Context::new(&mut bytes);
for op in list.iter() {
ctx.emit(*op).unwrap();
}
}
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, output);
}
#[test]
fn test_empty() {
emit_and_compare(&[
Opcode::Null(None, None, Null::Nothing),
], "");
}
#[test]
fn test_plain() {
emit_and_compare(&[
Opcode::Scalar(None, None, ScalarStyle::Auto, "hello"),
], "hello\n");
}
#[test]
fn test_map() {
emit_and_compare(&[
Opcode::MapStart(None, None),
Opcode::Scalar(None, None, ScalarStyle::Auto, "a"),
Opcode::Scalar(None, None, ScalarStyle::Auto, "val"),
Opcode::Scalar(None, None, ScalarStyle::Auto, "b"),
Opcode::Scalar(None, None, ScalarStyle::Auto, "2"),
Opcode::MapEnd,
], "a: val\nb: 2\n");
}
#[test]
fn test_map_null() {
emit_and_compare(&[
Opcode::MapStart(None, None),
Opcode::Scalar(None, None, ScalarStyle::Auto, "a"),
Opcode::Null(None, None, Null::Nothing),
Opcode::Scalar(None, None, ScalarStyle::Auto, "b"),
Opcode::Scalar(None, None, ScalarStyle::Auto, "2"),
Opcode::MapEnd,
], "a: \nb: 2\n");
}
fn assert_yaml_eq_yaml(source: &'static str, output: &'static str) {
let mut bytes = Vec::new();
let filen = Rc::new("<inline test>".to_string());
parse(filen.clone(), source, |doc| {
let mut ctx = Context::new(&mut bytes);
ctx.emit_node(&doc.root).unwrap();
}).unwrap();
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, output);
let mut bytes = Vec::new();
let err = ErrorCollector::new();
let ast = parse(filen, source, |doc| {
process(&Options::default(), doc, &err)
}).map_err(|e| err.into_fatal(e)).unwrap();
err.into_result(()).unwrap();
{
let mut ctx = Context::new(&mut bytes);
ctx.emit_ast(&ast).unwrap();
}
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, output);
}
#[test]
fn yaml_scalar() {
assert_yaml_eq_yaml("Hello", "Hello\n");
}
#[test]
fn yaml_tag_scalar() {
assert_yaml_eq_yaml("!Tag Hello", "!Tag Hello\n");
}
#[test]
fn yaml_tag_null() {
assert_yaml_eq_yaml("!Tag", "!Tag\n");
}
#[test]
fn yaml_map() {
assert_yaml_eq_yaml("a: b\nc: d", "a: b\nc: d\n");
}
#[test]
fn yaml_map_map() {
assert_yaml_eq_yaml("a:\n b: c", "a:\n b: c\n");
}
#[test]
fn yaml_list() {
assert_yaml_eq_yaml("- a\n- b", "- a\n- b\n");
}
#[test]
fn yaml_map_list() {
assert_yaml_eq_yaml("a:\n- b\n- c", "a:\n- b\n- c\n");
}
#[test]
fn yaml_list_map() {
assert_yaml_eq_yaml("- a: b\n c: d", "- a: b\n c: d\n");
}
#[test]
fn yaml_tag_map() {
assert_yaml_eq_yaml("!Tag {a: b}", "!Tag\na: b\n");
}
#[test]
fn yaml_null_in_map() {
assert_yaml_eq_yaml("a: \nb: x", "a: \nb: x\n");
}
#[test]
fn yaml_tag_null_in_map() {
assert_yaml_eq_yaml("a: !Tag\nb: x", "a: !Tag\nb: x\n");
}
#[test]
fn yaml_tag_null_in_map_nessted() {
assert_yaml_eq_yaml("x: \n a: !Tag\n b: x", "x:\n a: !Tag\n b: x\n");
}
#[test]
fn yaml_tag_null_in_map_unindent() {
assert_yaml_eq_yaml("x: \n a: !Tag\ny: z", "x:\n a: !Tag\ny: z\n");
}
#[test]
fn yaml_list_tag() {
assert_yaml_eq_yaml("- !Tag a", "- !Tag a\n");
}
#[test]
fn yaml_tag_map_map() {
assert_yaml_eq_yaml("a: !Tag\n a: b", "a: !Tag\n a: b\n");
}
#[test]
fn yaml_tag_map2() {
assert_yaml_eq_yaml("!Tag {a: b, c: d}", "!Tag\na: b\nc: d\n");
}
#[test]
fn yaml_tag_map3() {
assert_yaml_eq_yaml("!Tag { a: b, c: d }", "!Tag\na: b\nc: d\n");
}
#[test]
fn yaml_tag_list() {
assert_yaml_eq_yaml("!Tag [a, b, c]", "!Tag\n- a\n- b\n- c\n");
}
#[test]
fn encode_int() {
let mut bytes = Vec::new();
Context::to_buffer(&1usize, &mut bytes);
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, "1\n");
}
#[test]
fn encode_seq() {
let mut bytes = Vec::new();
Context::to_buffer(&vec!(1usize, 2usize), &mut bytes);
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, "- 1\n- 2\n");
}
#[derive(RustcEncodable)]
struct Something {
key1: isize,
key2: String,
}
#[test]
fn encode_struct() {
let mut bytes = Vec::new();
Context::to_buffer(&Something{
key1: -123,
key2: "hello".to_string(),
}, &mut bytes);
let value = from_utf8(&bytes[..]).unwrap();
assert_eq!(value, "key1: -123\nkey2: hello\n");
}
}