yaml-0.3.0/.gitignore010064426426055645743000000001141334130166700127260ustar0000000000000000.gitconfig target .DS_Store Cargo.lock # IntelliJ project directory /.idea yaml-0.3.0/.travis.yml010064426426055645743000000000351273207047100130500ustar0000000000000000language: rust rust: nightly yaml-0.3.0/build.rs010064426426055645743000000035651334130176200124140ustar0000000000000000use std::fs::File; use std::io::{stderr, Write}; use std::process::{Command, Output}; use std::path::Path; use std::env; fn run_cmd(command: &mut Command) -> Output { let stream = stderr(); let mut f = stream.lock(); let res = command.output(); match res { Ok(output) => if !output.status.success() { write!(&mut f, "Command `{:?}` failed", command).unwrap(); panic!("{}", String::from_utf8_lossy(&output.stderr[..])) } else { output }, Err(err) => { write!(&mut f, "Command `{:?}` failed", command).unwrap(); panic!("{}", err) } } } fn main() { let source_file = Path::new("src/codegen/type_size.c"); if !source_file.exists() { panic!("Could not find file: {}", source_file.to_string_lossy()); } let out_dir_var = match env::var("OUT_DIR") { Ok(dir) => dir, Err(e) => panic!("Could not get env value OUT_DIR: {}", e) }; let out_dir = Path::new(&out_dir_var); if !out_dir.exists() { panic!("Could not find directory: {}", out_dir.to_string_lossy()); } let out_file = out_dir.join("codegen"); let mut gcc_cmd = Command::new("gcc"); gcc_cmd.arg(source_file) .arg("-o").arg(&out_file); match env::var("LIBYAML_CFLAGS") { Ok(compile_flags) => { gcc_cmd.arg(&compile_flags); }, Err(_) => () } run_cmd(&mut gcc_cmd); let mut codegen_cmd = Command::new(&out_file); let output = run_cmd(&mut codegen_cmd); let generated_file = out_dir.join("type_size.rs"); let mut f = match File::create(generated_file) { Ok(f) => f, Err(e) => panic!("Could not open file $OUT_DIR/type_size.rs: {}", e) }; match f.write_all(&output.stdout[..]) { Err(e) => panic!("Could not write to $OUT_DIR/type_size.rs: {}", e), Ok(_) => () } } yaml-0.3.0/Cargo.toml.orig010064426426055645743000000004711334127762000136340ustar0000000000000000[package] name = "yaml" version = "0.3.0" authors = [ "kimhyunkang@gmail.com" ] build = "build.rs" description = "LibYAML binding for Rust" repository = "https://github.com/kimhyunkang/libyaml-rust" readme = "README.md" keywords = ["yaml", "libyaml"] license = "MIT" [dependencies] regex = "1.0" libc = "0.2" yaml-0.3.0/Cargo.toml0000644000000015370000000000000100410ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "yaml" version = "0.3.0" authors = ["kimhyunkang@gmail.com"] build = "build.rs" description = "LibYAML binding for Rust" readme = "README.md" keywords = ["yaml", "libyaml"] license = "MIT" repository = "https://github.com/kimhyunkang/libyaml-rust" [dependencies.libc] version = "0.2" [dependencies.regex] version = "1.0" yaml-0.3.0/LICENSE010064426426055645743000000020631273207047100117470ustar0000000000000000The MIT License (MIT) Copyright (c) 2014 김현강 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.yaml-0.3.0/README.md010064426426055645743000000026731334130066500122260ustar0000000000000000libyaml-rust ============ [![libyaml-rust on Travis CI][travis-image]][travis] [![yaml on crates.io][crates-image]][crate] [travis-image]: https://travis-ci.org/kimhyunkang/libyaml-rust.svg?branch=master [travis]: https://travis-ci.org/kimhyunkang/libyaml-rust [crates-image]: http://meritbadge.herokuapp.com/yaml [crate]: https://crates.io/crates/yaml [LibYAML][libyaml-home] bindings for [Rust][rust-home] [libyaml-home]: http://pyyaml.org/wiki/LibYAML [rust-home]: http://www.rust-lang.org/ Dependencies ------------ * LibYAML 0.1.4 or higher * Stable Rust (2015/2018 edition) Usage ----- Parse from memory ~~~~ {.rust} extern crate yaml; use yaml::constructor::*; yaml::parse_bytes_utf8("[1, 2, 3]".as_bytes()); // => Ok(vec![YamlSequence(~[YamlInteger(1), YamlInteger(2), YamlInteger(3)])]) ~~~~ Parse from Reader ~~~~ {.rust} extern crate yaml; use std::io::BufReader; use yaml::constructor::*; let data = "[1, 2, 3]"; let mut reader = BufReader::new(data.as_bytes()); yaml::parse_io_utf8(&mut reader); // => Ok(vec![YamlSequence(~[YamlInteger(1), YamlInteger(2), YamlInteger(3)])]) ~~~~ Todo ---- In the order of what I want to do... - [x] Emitter functions - [x] Document iterator - [x] UTF-16 support - Complete YAML 1.1 specs - [ ] Tag support - [ ] [Timestamp type](http://yaml.org/type/timestamp.html) - [ ] [Int parser](http://yaml.org/type/int.html) - [ ] [Float parser](http://yaml.org/type/float.html) - [ ] Token functions yaml-0.3.0/src/codecs.rs010064426426055645743000000012341273210441200133270ustar0000000000000000use ffi; use libc; use std::slice; use std::str; use std::ptr; use std::ffi::CStr; pub fn decode_c_str(c_str: *const ffi::yaml_char_t) -> Option { if c_str == ptr::null() { None } else { unsafe { let i8_str = c_str as *const i8; str::from_utf8(CStr::from_ptr(i8_str).to_bytes()).map(|s| s.to_string()).ok() } } } pub fn decode_buf(buf: *const ffi::yaml_char_t, length: libc::size_t) -> Option { if buf == ptr::null() { None } else { unsafe { str::from_utf8(slice::from_raw_parts(buf, length as usize)).map(|s| { s.to_string() }).ok() } } } yaml-0.3.0/src/codegen/type_size.c010064426426055645743000000071401273207047100153150ustar0000000000000000#include #include int main() { printf("use libc::c_int;\n\n"); printf("#[allow(non_camel_case_types)]\n"); printf("pub type yaml_parser_mem_t = [c_int; %lu];\n", sizeof(yaml_parser_t) / sizeof(int)); printf("pub fn new_yaml_parser_mem_t() -> yaml_parser_mem_t {\n"); printf(" [0; %lu]\n", sizeof(yaml_parser_t) / sizeof(int)); printf("}\n\n"); yaml_event_t dummy_event; printf("#[allow(non_camel_case_types)]\n"); printf("pub type yaml_event_data_t = [c_int; %lu];\n", sizeof(dummy_event.data) / sizeof(int)); printf("pub fn new_yaml_event_data_t() -> yaml_event_data_t {\n"); printf(" [0; %lu]\n", sizeof(dummy_event.data) / sizeof(int)); printf("}\n\n"); printf("#[allow(non_camel_case_types)]\n"); printf("#[repr(u%lu)]\n", ((size_t)(&dummy_event.data) - (size_t)(&dummy_event)) * 8); printf("#[derive(Debug, PartialEq, Clone, Copy)]\n"); printf("pub enum yaml_event_type_t {\n"); printf(" /** An empty event. */\n"); printf(" YAML_NO_EVENT = 0,\n\n"); printf(" /** A STREAM-START event. */\n"); printf(" YAML_STREAM_START_EVENT,\n"); printf(" /** A STREAM-END event. */\n"); printf(" YAML_STREAM_END_EVENT,\n\n"); printf(" /** A DOCUMENT-START event. */\n"); printf(" YAML_DOCUMENT_START_EVENT,\n"); printf(" /** A DOCUMENT-END event. */\n"); printf(" YAML_DOCUMENT_END_EVENT,\n\n"); printf(" /** An ALIAS event. */\n"); printf(" YAML_ALIAS_EVENT,\n"); printf(" /** A SCALAR event. */\n"); printf(" YAML_SCALAR_EVENT,\n\n"); printf(" /** A SEQUENCE-START event. */\n"); printf(" YAML_SEQUENCE_START_EVENT,\n"); printf(" /** A SEQUENCE-END event. */\n"); printf(" YAML_SEQUENCE_END_EVENT,\n\n"); printf(" /** A MAPPING-START event. */\n"); printf(" YAML_MAPPING_START_EVENT,\n"); printf(" /** A MAPPING-END event. */\n"); printf(" YAML_MAPPING_END_EVENT\n"); printf("}\n\n"); yaml_parser_t dummy_parser; printf("#[allow(non_camel_case_types)]\n"); printf("pub type yaml_parser_input_t = [c_int; %lu];\n\n", sizeof(dummy_parser.input) / sizeof(int)); printf("pub fn new_yaml_parser_input_t() -> yaml_parser_input_t {\n"); printf(" [0; %lu]\n", sizeof(dummy_parser.input) / sizeof(int)); printf("}\n\n"); yaml_emitter_t dummy_emitter; printf("#[allow(non_camel_case_types)]\n"); printf("pub type yaml_emitter_output_t = [c_int; %lu];\n\n", sizeof(dummy_emitter.output) / sizeof(int)); printf("pub fn new_yaml_emitter_output_t() -> yaml_emitter_output_t {\n"); printf(" [0; %lu]\n", sizeof(dummy_emitter.output) / sizeof(int)); printf("}\n\n"); yaml_node_t dummy_node; printf("#[allow(non_camel_case_types)]\n"); printf("pub type yaml_node_data_t = [c_int; %lu];\n\n", sizeof(dummy_node.data) / sizeof(int)); printf("pub fn new_yaml_node_data_t() -> yaml_node_data_t {\n"); printf(" [0; %lu]\n", sizeof(dummy_node.data) / sizeof(int)); printf("}\n\n"); printf("#[cfg(test)]\n"); printf("pub static YAML_PARSER_T_SIZE:usize = %lu;\n", sizeof(yaml_parser_t)); printf("#[cfg(test)]\n"); printf("pub static YAML_EMITTER_T_SIZE:usize = %lu;\n", sizeof(yaml_emitter_t)); printf("#[cfg(test)]\n"); printf("pub static YAML_EVENT_T_SIZE:usize = %lu;\n", sizeof(yaml_event_t)); printf("#[cfg(test)]\n"); printf("pub static YAML_DOCUMENT_T_SIZE:usize = %lu;\n", sizeof(yaml_document_t)); printf("#[cfg(test)]\n"); printf("pub static YAML_NODE_T_SIZE:usize = %lu;\n", sizeof(yaml_node_t)); return 0; } yaml-0.3.0/src/constructor.rs010064426426055645743000000375261306425570400145030ustar0000000000000000use document; use document::{YamlNode, YamlNodeData}; use ffi::{YamlErrorType, YamlScalarStyle}; use error::{YamlMark, YamlError, YamlErrorContext}; use std::f64; use std::char; use regex::Regex; pub trait YamlConstructor { fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result; fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result; fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result; fn construct<'r>(&self, node: document::YamlNode<'r>) -> Result { match node { YamlNode::YamlScalarNode(scalar) => self.construct_scalar(scalar), YamlNode::YamlSequenceNode(sequence) => self.construct_sequence(sequence), YamlNode::YamlMappingNode(mapping) => self.construct_mapping(mapping) } } } #[derive(PartialEq, Clone, Debug)] pub enum YamlStandardData { YamlInteger(isize), YamlFloat(f64), YamlString(String), YamlNull, YamlBool(bool), YamlSequence(Vec), YamlMapping(Vec<(YamlStandardData, YamlStandardData)>), } #[derive(Clone)] pub struct YamlStandardConstructor { dec_int_pat:Regex, oct_int_pat:Regex, hex_int_pat:Regex, bin_int_pat:Regex, flt_pat:Regex, pos_inf_pat:Regex, neg_inf_pat:Regex, nan_pat:Regex, null_pat:Regex, true_pat:Regex, false_pat:Regex } fn standard_error(message: String, mark: &YamlMark) -> YamlError { let context = YamlErrorContext { byte_offset: mark.index, problem_mark: *mark, context: None, context_mark: *mark, }; YamlError { kind: YamlErrorType::YAML_PARSER_ERROR, problem: Some(message), io_error: None, context: Some(context) } } fn take(iter: &mut Iterator, n: usize) -> String { let mut s = String::new(); for _ in 0..n { match iter.next() { Some(c) => s.push(c), None => break } } return s; } impl YamlStandardConstructor { pub fn new() -> YamlStandardConstructor { YamlStandardConstructor { dec_int_pat: Regex::new(r"^[-+]?(0|[1-9][0-9_]*)$").unwrap(), oct_int_pat: Regex::new(r"^([-+]?)0o?([0-7_]+)$").unwrap(), hex_int_pat: Regex::new(r"^([-+]?)0x([0-9a-fA-F_]+)$").unwrap(), bin_int_pat: Regex::new(r"^([-+]?)0b([0-1_]+)$").unwrap(), flt_pat: Regex::new(r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$").unwrap(), pos_inf_pat: Regex::new(r"^[+]?(\.inf|\.Inf|\.INF)$").unwrap(), neg_inf_pat: Regex::new(r"^-(\.inf|\.Inf|\.INF)$").unwrap(), nan_pat: Regex::new(r"^(\.nan|\.NaN|\.NAN)$").unwrap(), null_pat: Regex::new(r"^(null|Null|NULL|~)$").unwrap(), true_pat: Regex::new(r"^(true|True|TRUE|yes|Yes|YES)$").unwrap(), false_pat: Regex::new(r"^(false|False|FALSE|no|No|NO)$").unwrap() } } fn parse_double_quoted(value: &str, mark: &YamlMark) -> Result { let mut buf = String::new(); let mut it = value.chars(); loop { match it.next() { None => return Ok(buf), Some('\\') => { // escape sequences match it.next() { None => return Err(standard_error( "unexpected end of string after escape".to_string(), mark )), Some('0') => buf.push('\x00'), // null Some('a') => buf.push('\x07'), // ASCII bell Some('b') => buf.push('\x08'), // backspace Some('t') | Some('\t') => buf.push('\t'), // horizontal tab Some('n') => buf.push('\n'), // linefeed Some('v') => buf.push('\x0b'), // vertical tab Some('f') => buf.push('\x0c'), // form feed Some('r') => buf.push('\x0d'), // carriage return Some('e') => buf.push('\x1b'), // ASCII escape Some('N') => buf.push('\u{85}'), // unicode next line Some('_') => buf.push('\u{a0}'), // unicode non-breaking space Some('L') => buf.push('\u{2028}'), // unicode line separator Some('P') => buf.push('\u{2029}'), // unicode paragraph separator Some('x') => { let code:String = take(&mut it, 2); match parse_escape_sequence(&code[..], 2) { Some(c) => buf.push(c), None => return Err(standard_error( format!("invalid escape sequence {}", code), mark )) } }, Some('u') => { let code:String = take(&mut it, 4); match parse_escape_sequence(&code[..], 4) { Some(c) => buf.push(c), None => return Err(standard_error( format!("invalid escape sequence {}", code), mark )) } }, Some('U') => { let code:String = take(&mut it, 8); match parse_escape_sequence(&code[..], 8) { Some(c) => buf.push(c), None => return Err(standard_error( format!("invalid escape sequence {}", code), mark )) } }, Some(c) => buf.push(c) } }, Some(c) => buf.push(c) } } } } fn parse_escape_sequence(rep: &str, expected_len: usize) -> Option { match u32::from_str_radix(rep, 16) { Ok(code) if rep.len() == expected_len => char::from_u32(code), _ => None } } fn parse_int(sign: &str, data: &str, radix: u32) -> isize { let sign_flag = if sign == "-" { -1 } else { 1 }; let filtered:String = data.chars().filter(|&c| c != '_').collect(); let unsigned:isize = isize::from_str_radix(&filtered[..], radix).unwrap(); return unsigned * sign_flag; } fn parse_float(sign: &str, data: &str) -> f64 { let unsigned:f64 = data.parse().unwrap(); if sign == "-" { return -unsigned; } else { return unsigned; } } impl YamlConstructor for YamlStandardConstructor { fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result { let value = scalar.get_value(); let mark = scalar.start_mark(); match scalar.style() { YamlScalarStyle::YamlPlainScalarStyle => { match self.bin_int_pat.captures(&value[..]) { Some(caps) => return Ok(YamlStandardData::YamlInteger(parse_int( &caps[1], &caps[2], 2))), None => () }; match self.oct_int_pat.captures(&value[..]) { Some(caps) => return Ok(YamlStandardData::YamlInteger(parse_int( &caps[1], &caps[2], 8))), None => () }; match self.hex_int_pat.captures(&value[..]) { Some(caps) => return Ok(YamlStandardData::YamlInteger(parse_int( &caps[1], &caps[2], 16))), None => () }; if self.dec_int_pat.is_match(&value[..]) { return Ok(YamlStandardData::YamlInteger(parse_int("", &value[..], 10))); } match self.flt_pat.captures(&value[..]) { Some(caps) => return Ok(YamlStandardData::YamlFloat(parse_float( &caps[1], &caps[2]))), None => () }; if self.pos_inf_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlFloat(f64::INFINITY)) } else if self.neg_inf_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlFloat(f64::NEG_INFINITY)) } else if self.nan_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlFloat(f64::NAN)) } else if self.null_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlNull) } else if self.true_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlBool(true)) } else if self.false_pat.is_match(&value[..]) { Ok(YamlStandardData::YamlBool(false)) } else { Ok(YamlStandardData::YamlString(value)) } }, YamlScalarStyle::YamlDoubleQuotedScalarStyle => { YamlStandardConstructor::parse_double_quoted(&value[..], &mark).map(YamlStandardData::YamlString) }, _ => { Ok(YamlStandardData::YamlString(value)) } } } fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result { let res:Result, YamlError> = sequence.values().map(|node| { self.construct(node) }).collect(); res.map(|list| YamlStandardData::YamlSequence(list)) } fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result { let pairs = mapping.pairs().map(|(key_node, value_node)| { match self.construct(key_node) { Ok(key) => match self.construct(value_node) { Ok(value) => Ok((key, value)), Err(e) => Err(e) }, Err(e) => Err(e) } }); let res:Result, YamlError> = pairs.collect(); res.map(YamlStandardData::YamlMapping) } } #[cfg(test)] mod test { use super::YamlStandardData::*; use parser::{YamlParser, YamlByteParser}; use std::f64; use ffi::YamlEncoding::YamlUtf8Encoding; use constructor::{YamlConstructor, YamlStandardConstructor}; #[test] fn test_standard_constructor() { let data = "[1, 2, 3]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])), ctor.construct(doc.root().unwrap())) }, _ => panic!("unexpected result") } } #[test] fn test_integer_parser() { let data = "[0o10, 0x21, -30]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlInteger(0o10), YamlInteger(0x21), YamlInteger(-30)])), ctor.construct(doc.root().unwrap())) }, _ => panic!("unexpected result") } } #[test] fn test_float_parser() { let data = "[0.3, -.4, 1e+2, -1.2e-3]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); let value = ctor.construct(doc.root().unwrap()); match value { Ok(YamlSequence(seq)) => { match &seq[..] { &[YamlFloat(f1), YamlFloat(f2), YamlFloat(f3), YamlFloat(f4)] => { assert!((f1 - 0.3).abs() < 1.0e-6); assert!((f2 + 0.4) < 1.0e-6); assert!((f3 - 1e+2) < 1.0e-6); assert!((f4 + 1.2e-3) < 1.0e-6); }, _ => panic!("unexpected sequence") } }, _ => panic!("unexpected result") } }, _ => panic!("document parse failure") } } #[test] fn test_inf_parser() { let data = "[.inf, -.INF]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlFloat(f64::INFINITY), YamlFloat(f64::NEG_INFINITY)])), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } #[test] fn test_misc_parser() { let data = "[yes, False, ~]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlBool(true), YamlBool(false), YamlNull])), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } #[test] fn test_double_quoted_parser() { let data = r#""hello, \"world\"""#; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlString("hello, \"world\"".to_string())), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } #[test] fn test_single_quoted_parser() { let data = r#"'here''s to "quotes"'"#; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlString(r#"here's to "quotes""#.to_string())), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } #[test] fn test_underlined_integer() { let data = "[1_000, -2_000_000]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlInteger(1000), YamlInteger(-2000000)])), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } #[test] fn test_negative_radix() { let data = "[-0x30, -0700, -0b110]"; let parser = YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); match parser.load().next() { Some(Ok(doc)) => { let ctor = YamlStandardConstructor::new(); assert_eq!(Ok(YamlSequence(vec![YamlInteger(-48), YamlInteger(-448), YamlInteger(-6)])), ctor.construct(doc.root().unwrap())) }, _ => panic!("document parse failure") } } } yaml-0.3.0/src/document.rs010064426426055645743000000135511334127756100137270ustar0000000000000000use libc; use codecs; use ffi; use ffi::yaml_node_type_t::*; use error::YamlMark; use std::ptr; use std::mem; pub struct YamlDocument { document_mem: ffi::yaml_document_t } impl YamlDocument { pub unsafe fn parser_load(parser: &mut ffi::yaml_parser_t) -> Option> { let mut document = Box::new(YamlDocument { document_mem: mem::uninitialized() }); if ffi::yaml_parser_load(parser, &mut document.document_mem) == 0 { None } else { Some(document) } } pub fn is_empty(&self) -> bool { unsafe { ffi::yaml_document_get_root_node(&self.document_mem) == ptr::null() } } unsafe fn load<'r>(&'r self, node_ptr: *const ffi::yaml_node_t) -> YamlNode<'r> { if node_ptr == ptr::null() { panic!("empty node") } let node = &*node_ptr; match node.node_type { YAML_SCALAR_NODE => { let scalar_data: &ffi::yaml_scalar_node_t = mem::transmute(&node.data); YamlNode::YamlScalarNode(YamlScalarData { node: node, data: scalar_data }) }, YAML_SEQUENCE_NODE => { let sequence_data: &ffi::yaml_sequence_node_t = mem::transmute(&node.data); YamlNode::YamlSequenceNode(YamlSequenceData { doc: self, node: node, data: sequence_data }) }, YAML_MAPPING_NODE => { let mapping_data: &ffi::yaml_sequence_node_t = mem::transmute(&node.data); YamlNode::YamlMappingNode(YamlMappingData { doc: self, node: node, data: mapping_data }) }, _ => panic!("invalid node") } } unsafe fn get_node<'r>(&'r self, index: libc::c_int) -> YamlNode<'r> { let node_ptr = ffi::yaml_document_get_node(&self.document_mem, index); self.load(node_ptr) } pub fn root<'r>(&'r self) -> Option> { unsafe { let node_ptr = ffi::yaml_document_get_root_node(&self.document_mem); if node_ptr == ptr::null() { None } else { Some(self.load(node_ptr)) } } } } impl Drop for YamlDocument { fn drop(&mut self) { unsafe { ffi::yaml_document_delete(&mut self.document_mem); } } } pub enum YamlNode<'r> { YamlScalarNode(YamlScalarData<'r>), YamlSequenceNode(YamlSequenceData<'r>), YamlMappingNode(YamlMappingData<'r>), } pub trait YamlNodeData { unsafe fn internal_node<'r>(&'r self) -> &'r ffi::yaml_node_t; fn tag(&self) -> Option { unsafe { codecs::decode_c_str(self.internal_node().tag) } } fn start_mark(&self) -> YamlMark { unsafe { YamlMark::conv(&self.internal_node().start_mark) } } fn end_mark(&self) -> YamlMark { unsafe { YamlMark::conv(&self.internal_node().end_mark) } } } pub struct YamlScalarData<'r> { node: &'r ffi::yaml_node_t, data: &'r ffi::yaml_scalar_node_t } impl<'r> YamlNodeData for YamlScalarData<'r> { unsafe fn internal_node<'a>(&'a self) -> &'a ffi::yaml_node_t { self.node } } impl<'r> YamlScalarData<'r> { pub fn get_value(&self) -> String { codecs::decode_buf(self.data.value, self.data.length).unwrap() } pub fn style(&self) -> ffi::YamlScalarStyle { self.data.style } } pub struct YamlSequenceData<'r> { doc: &'r YamlDocument, node: &'r ffi::yaml_node_t, data: &'r ffi::yaml_sequence_node_t } impl<'r> YamlNodeData for YamlSequenceData<'r> { unsafe fn internal_node<'a>(&'a self) -> &'a ffi::yaml_node_t { self.node } } impl<'r> YamlSequenceData<'r> { pub fn values(&self) -> YamlSequenceIter<'r> { YamlSequenceIter { doc: self.doc, top: self.data.items.top as *const libc::c_int, ptr: self.data.items.start as *const libc::c_int } } } pub struct YamlSequenceIter<'r> { doc: &'r YamlDocument, top: *const libc::c_int, ptr: *const libc::c_int } impl<'r> Iterator for YamlSequenceIter<'r> { type Item = YamlNode<'r>; fn next(&mut self) -> Option> { if self.ptr == self.top { None } else { unsafe { let next_node = self.doc.get_node(*self.ptr); self.ptr = self.ptr.offset(1); Some(next_node) } } } } pub struct YamlMappingData<'r> { doc: &'r YamlDocument, node: &'r ffi::yaml_node_t, data: &'r ffi::yaml_sequence_node_t } impl<'r> YamlNodeData for YamlMappingData<'r> { unsafe fn internal_node<'a>(&'a self) -> &'a ffi::yaml_node_t { self.node } } impl<'r> YamlMappingData<'r> { pub fn pairs(&self) -> YamlMappingIter<'r> { YamlMappingIter { doc: self.doc, top: self.data.items.top as *const ffi::yaml_node_pair_t, ptr: self.data.items.start as *const ffi::yaml_node_pair_t } } } pub struct YamlMappingIter<'r> { doc: &'r YamlDocument, top: *const ffi::yaml_node_pair_t, ptr: *const ffi::yaml_node_pair_t } impl<'r> Iterator for YamlMappingIter<'r> { type Item = (YamlNode<'r>, YamlNode<'r>); fn next(&mut self) -> Option<(YamlNode<'r>, YamlNode<'r>)> { if self.ptr == self.top { None } else { unsafe { let next_key = self.doc.get_node((*self.ptr).key); let next_value = self.doc.get_node((*self.ptr).value); self.ptr = self.ptr.offset(1); Some((next_key, next_value)) } } } } yaml-0.3.0/src/emitter.rs010064426426055645743000000357241334127756100135700ustar0000000000000000use ffi; use error::YamlError; use event::{YamlVersionDirective, YamlTagDirective}; use std::str; use std::slice; use std::ptr; use std::mem; use std::ffi::{CStr, CString}; use std::io; use std::io::Write; use libc; pub struct YamlBaseEmitter { emitter_mem: ffi::yaml_emitter_t } impl YamlBaseEmitter { unsafe fn new() -> YamlBaseEmitter { YamlBaseEmitter { emitter_mem: mem::uninitialized() } } } impl Drop for YamlBaseEmitter { fn drop(&mut self) { unsafe { ffi::yaml_emitter_delete(&mut self.emitter_mem); } } } pub struct YamlEmitter<'r> { base_emitter: YamlBaseEmitter, writer: &'r mut (Write+'r), io_error: Option, } fn to_c_str_opt(s: Option<&str>) -> Result, YamlError> { match s { None => Ok(None), Some(s) => match CString::new(s.as_bytes()) { Ok(cstr) => Ok(Some(cstr)), Err(_) => Err(YamlError::new( ffi::YamlErrorType::YAML_EMITTER_ERROR, Some("Nul bytes in string".to_string()) )) } } } fn to_c_str(s: &str) -> Result { match CString::new(s.as_bytes()) { Ok(cstr) => Ok(cstr), Err(_) => Err(YamlError::new( ffi::YamlErrorType::YAML_EMITTER_ERROR, Some("Nul bytes in string".to_string()) )) } } impl<'r> YamlEmitter<'r> { pub fn init<'a>(writer: &'a mut Write) -> Box> { unsafe { let mut emitter = Box::new(YamlEmitter { base_emitter: YamlBaseEmitter::new(), writer: writer, io_error: None }); if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 { panic!("failed to initialize yaml_emitter_t"); } ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, mem::transmute(&mut *emitter)); emitter } } fn get_error(&mut self) -> YamlError { let emitter_mem = &self.base_emitter.emitter_mem; unsafe { let c_problem = CStr::from_ptr(emitter_mem.problem); let mut error = YamlError { kind: emitter_mem.error, problem: str::from_utf8(c_problem.to_bytes()).map(|s| s.to_string()).ok(), io_error: None, context: None }; mem::swap(&mut self.io_error, &mut error.io_error); return error; } } pub fn emit_stream(&mut self, encoding: ffi::YamlEncoding, f: F) -> Result<(), YamlError> where F: Fn(&mut YamlEmitter) -> Result<(), YamlError> { try!(self.emit_stream_start_event(encoding)); try!(f(self)); try!(self.emit_stream_end_event()); self.flush() } fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), YamlError> { unsafe { let mut event = mem::uninitialized(); if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 { panic!("yaml_stream_start_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } fn emit_stream_end_event(&mut self) -> Result<(), YamlError> { unsafe { let mut event = mem::uninitialized(); if ffi::yaml_stream_end_event_initialize(&mut event) == 0 { panic!("yaml_stream_end_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn emit_document(&mut self, version_directive: Option, tag_directives: &[YamlTagDirective], implicit: bool, f: F) -> Result<(), YamlError> where F: Fn(&mut YamlEmitter) -> Result<(), YamlError> { try!(self.emit_document_start_event(version_directive, tag_directives, implicit)); try!(f(self)); self.emit_document_end_event(implicit) } fn emit_document_start_event(&mut self, version_directive: Option, tag_directives: &[YamlTagDirective], implicit: bool) -> Result<(), YamlError> { let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 }; let c_vsn_dir = match version_directive { Some(directive) => { vsn_dir.major = directive.major as libc::c_int; vsn_dir.minor = directive.minor as libc::c_int; &vsn_dir as *const ffi::yaml_version_directive_t }, None => ptr::null() }; let c_tag_dirs: Vec = match tag_directives.iter().map(|tag| tag.to_tag_directive_t()).collect() { Ok(dirs) => dirs, Err(_) => return Err(YamlError::new( ffi::YamlErrorType::YAML_EMITTER_ERROR, Some("Nul bytes in tag directives".to_string()) )) }; let tag_dir_start = c_tag_dirs.as_ptr(); unsafe { let mut event = mem::uninitialized(); let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as isize); let c_implicit = if implicit { 1 } else { 0 }; if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 { panic!("yaml_document_start_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), YamlError> { let c_implicit = if implicit { 1 } else { 0 }; unsafe { let mut event = mem::uninitialized(); if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 { panic!("yaml_stream_end_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), YamlError> { let c_anchor = try!(to_c_str(anchor)); unsafe { let mut event = mem::uninitialized(); let ptr = c_anchor.as_ptr(); if ffi::yaml_alias_event_initialize(&mut event, ptr as *const ffi::yaml_char_t) != 0 { panic!("yaml_stream_end_event_initialize failed!") } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>, value: &str, plain_implicit: bool, quoted_implicit: bool, style: ffi::YamlScalarStyle) -> Result<(), YamlError> { let c_anchor = try!(to_c_str_opt(anchor)); let anchor_ptr = match c_anchor { Some(s) => s.as_ptr(), None => ptr::null() }; let c_tag = try!(to_c_str_opt(tag)); let tag_ptr = match c_tag { Some(s) => s.as_ptr(), None => ptr::null() }; let c_plain_implicit = if plain_implicit { 1 } else { 0 }; let c_quoted_implicit = if quoted_implicit { 1 } else { 0 }; unsafe { let mut event = mem::uninitialized(); if ffi::yaml_scalar_event_initialize(&mut event, anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t, value.as_ptr(), value.len() as libc::c_int, c_plain_implicit, c_quoted_implicit, style) == 0 { panic!("yaml_scalar_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn emit_sequence(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool, style: ffi::YamlSequenceStyle, f: F) -> Result<(), YamlError> where F: Fn(&mut YamlEmitter) -> Result<(), YamlError> { try!(self.emit_sequence_start_event(anchor, tag, implicit, style)); try!(f(self)); self.emit_sequence_end_event() } fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool, style: ffi::YamlSequenceStyle) -> Result<(), YamlError> { let c_anchor = try!(to_c_str_opt(anchor)); let anchor_ptr = match c_anchor { Some(s) => s.as_ptr(), None => ptr::null() }; let c_tag = try!(to_c_str_opt(tag)); let tag_ptr = match c_tag { Some(s) => s.as_ptr(), None => ptr::null() }; let c_implicit = if implicit { 1 } else { 0 }; unsafe { let mut event = mem::uninitialized(); if ffi::yaml_sequence_start_event_initialize(&mut event, anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t, c_implicit, style) == 0 { panic!("yaml_sequence_start_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } fn emit_sequence_end_event(&mut self) -> Result<(), YamlError> { unsafe { let mut event = mem::uninitialized(); if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 { panic!("yaml_sequence_end_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn emit_mapping(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool, style: ffi::YamlSequenceStyle, f: F) -> Result<(), YamlError> where F: Fn(&mut YamlEmitter) -> Result<(), YamlError> { try!(self.emit_mapping_start_event(anchor, tag, implicit, style)); try!(f(self)); self.emit_mapping_end_event() } fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool, style: ffi::YamlSequenceStyle) -> Result<(), YamlError> { let c_anchor = try!(to_c_str_opt(anchor)); let anchor_ptr = match c_anchor { Some(s) => s.as_ptr(), None => ptr::null() }; let c_tag = try!(to_c_str_opt(tag)); let tag_ptr = match c_tag { Some(s) => s.as_ptr(), None => ptr::null() }; let c_implicit = if implicit { 1 } else { 0 }; unsafe { let mut event = mem::uninitialized(); if ffi::yaml_mapping_start_event_initialize(&mut event, anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t, c_implicit, style) == 0 { panic!("yaml_mapping_start_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } fn emit_mapping_end_event(&mut self) -> Result<(), YamlError> { unsafe { let mut event = mem::uninitialized(); if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 { panic!("yaml_mapping_end_event_initialize failed!"); } if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 { Ok(()) } else { Err(self.get_error()) } } } pub fn flush(&mut self) -> Result<(), YamlError> { unsafe { if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 { Ok(()) } else { Err(self.get_error()) } } } } extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *const u8, size: libc::size_t) -> libc::c_int { unsafe { let buf = slice::from_raw_parts(buffer, size as usize); let emitter = &mut *data; match emitter.writer.write_all(buf) { Ok(()) => 1, Err(err) => { emitter.io_error = Some(err); 0 } } } } #[cfg(test)] mod test { use emitter::YamlEmitter; use ffi::YamlEncoding::YamlUtf8Encoding; use ffi::YamlScalarStyle::*; use ffi::YamlSequenceStyle::*; #[test] #[allow(unused_must_use)] fn event_emitter_sequence_test() { let mut writer = Vec::new(); { let mut emitter = YamlEmitter::init(&mut writer); emitter.emit_stream(YamlUtf8Encoding, |e| { e.emit_document(None, &[], true, |e| { e.emit_sequence(None, None, true, YamlFlowSequenceStyle, |e| { try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle)); e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle) }) }) }); emitter.flush(); } assert_eq!(&writer[..], b"[1, 2]\n"); } #[test] #[allow(unused_must_use)] fn event_emitter_mapping_test() { let mut writer = Vec::new(); { let mut emitter = YamlEmitter::init(&mut writer); emitter.emit_stream(YamlUtf8Encoding, |e| { e.emit_document(None, &[], true, |e| { e.emit_mapping(None, None, true, YamlFlowSequenceStyle, |e| { try!(e.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle)); try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle)); try!(e.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle)); e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle) }) }) }); emitter.flush(); } assert_eq!(&writer[..], b"{a: 1, b: 2}\n"); } } yaml-0.3.0/src/error.rs010064426426055645743000000046501273210450600132310ustar0000000000000000use std::error::Error; use std::io; use std::fmt; use ffi; use ffi::YamlErrorType; #[derive(Debug, PartialEq, Clone, Copy)] pub struct YamlMark { pub index: usize, pub line: usize, pub column: usize } impl YamlMark { pub fn conv(mark: &ffi::yaml_mark_t) -> YamlMark { YamlMark { index: mark.index as usize, line: mark.line as usize, column: mark.column as usize } } } #[derive(Debug, PartialEq)] pub struct YamlErrorContext { pub byte_offset: usize, pub problem_mark: YamlMark, pub context: Option, pub context_mark: YamlMark } #[derive(Debug)] pub struct YamlError { pub kind: YamlErrorType, pub problem: Option, pub io_error: Option, pub context: Option } impl PartialEq for YamlError { fn eq(&self, rhs: &YamlError) -> bool { self.kind == rhs.kind && self.problem == rhs.problem && self.io_error.is_none() && rhs.io_error.is_none() && self.context == rhs.context } } impl Error for YamlError { fn description(&self) -> &str { match self.kind { YamlErrorType::YAML_NO_ERROR => "No error is produced", YamlErrorType::YAML_MEMORY_ERROR => "Cannot allocate or reallocate a block of memory", YamlErrorType::YAML_READER_ERROR => "Cannot read or decode the input stream", YamlErrorType::YAML_SCANNER_ERROR => "Cannot scan the input stream", YamlErrorType::YAML_PARSER_ERROR => "Cannot parse the input stream", YamlErrorType::YAML_COMPOSER_ERROR => "Cannot compose a YAML document", YamlErrorType::YAML_WRITER_ERROR => "Cannot write to the output stream", YamlErrorType::YAML_EMITTER_ERROR => "Cannot emit a YAML stream", } } fn cause(&self) -> Option<&Error> { match self.io_error { None => None, Some(ref e) => Some(e as &Error) } } } impl YamlError { pub fn new(kind: YamlErrorType, problem: Option) -> YamlError { YamlError { kind: kind, problem: problem, io_error: None, context: None } } } impl fmt::Display for YamlError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.problem { None => return Ok(()), Some(ref s) => s.fmt(f) } } } yaml-0.3.0/src/event.rs010064426426055645743000000137731273207047100132320ustar0000000000000000use ffi; use ffi::{YamlEncoding, YamlSequenceStyle, YamlScalarStyle}; use ffi::yaml_event_type_t::*; use std::ffi::{CString, NulError}; use std::mem; use std::ptr; use codecs; use ::error::YamlMark; #[derive(Debug, PartialEq, Clone, Copy)] pub struct YamlVersionDirective { pub major: isize, pub minor: isize, } #[derive(Debug, PartialEq)] pub struct YamlTagDirective { pub handle: String, pub prefix: String, } impl YamlTagDirective { pub fn to_tag_directive_t(&self) -> Result { let handle = try!(CString::new(self.handle.as_bytes())); let prefix = try!(CString::new(self.prefix.as_bytes())); Ok(ffi::yaml_tag_directive_t { handle: handle.as_ptr(), prefix: prefix.as_ptr() }) } } #[derive(Debug, PartialEq)] pub struct YamlSequenceParam { pub anchor: Option, pub tag: Option, pub implicit: bool, pub style: YamlSequenceStyle } #[derive(Debug, PartialEq)] pub struct YamlScalarParam { pub anchor: Option, pub tag: Option, pub value: String, pub plain_implicit: bool, pub quoted_implicit: bool, pub style: YamlScalarStyle } #[derive(Debug, PartialEq)] pub enum YamlEventSpec { YamlNoEvent, YamlStreamStartEvent(YamlEncoding), YamlStreamEndEvent, YamlDocumentStartEvent(Option, Vec, bool), YamlDocumentEndEvent(bool), YamlAliasEvent(String), YamlScalarEvent(YamlScalarParam), YamlSequenceStartEvent(YamlSequenceParam), YamlSequenceEndEvent, YamlMappingStartEvent(YamlSequenceParam), YamlMappingEndEvent, } #[derive(Debug)] pub struct YamlEvent { pub spec: YamlEventSpec, pub start: YamlMark, pub end: YamlMark } impl YamlEvent { pub unsafe fn load(event: &ffi::yaml_event_t) -> YamlEvent { YamlEvent { spec: YamlEvent::load_spec(event), start: YamlMark::conv(&event.start_mark), end: YamlMark::conv(&event.end_mark) } } unsafe fn load_spec(event: &ffi::yaml_event_t) -> YamlEventSpec { match event.event_type { YAML_NO_EVENT => YamlEventSpec::YamlNoEvent, YAML_STREAM_START_EVENT => { let evt_data: &ffi::yaml_stream_start_event_t = mem::transmute(&event.data); YamlEventSpec::YamlStreamStartEvent(evt_data.encoding) }, YAML_STREAM_END_EVENT => YamlEventSpec::YamlStreamEndEvent, YAML_DOCUMENT_START_EVENT => { let evt_data: &ffi::yaml_document_start_event_t = mem::transmute(&event.data); let vsn_dir = if evt_data.version_directive == ptr::null() { None } else { let c_vsn_dir: &ffi::yaml_version_directive_t = mem::transmute(evt_data.version_directive); Some(YamlVersionDirective { major: c_vsn_dir.major as isize, minor: c_vsn_dir.minor as isize }) }; let mut tag_dirs = Vec::new(); let mut tag_ptr = evt_data.tag_directives.start; while tag_ptr != ptr::null() && tag_ptr != evt_data.tag_directives.end { let tag_ref: &ffi::yaml_tag_directive_t = mem::transmute(tag_ptr); let handle = codecs::decode_c_str(tag_ref.handle as *const ffi::yaml_char_t).unwrap(); let prefix = codecs::decode_c_str(tag_ref.prefix as *const ffi::yaml_char_t).unwrap(); tag_dirs.push(YamlTagDirective { handle: handle, prefix: prefix }); tag_ptr = tag_ptr.offset(1); } let implicit = evt_data.implicit != 0; YamlEventSpec::YamlDocumentStartEvent(vsn_dir, tag_dirs, implicit) }, YAML_DOCUMENT_END_EVENT => { let evt_data: &ffi::yaml_document_end_event_t = mem::transmute(&event.data); let implicit = evt_data.implicit != 0; YamlEventSpec::YamlDocumentEndEvent(implicit) }, YAML_ALIAS_EVENT => { let evt_data: &ffi::yaml_alias_event_t = mem::transmute(&event.data); let anchor = codecs::decode_c_str(evt_data.anchor).unwrap(); YamlEventSpec::YamlAliasEvent(anchor) }, YAML_SCALAR_EVENT => { let evt_data: &ffi::yaml_scalar_event_t = mem::transmute(&event.data); let value = codecs::decode_buf(evt_data.value, evt_data.length).unwrap(); YamlEventSpec::YamlScalarEvent(YamlScalarParam { anchor: codecs::decode_c_str(evt_data.anchor), tag: codecs::decode_c_str(evt_data.tag), value: value, plain_implicit: evt_data.plain_implicit != 0, quoted_implicit: evt_data.quoted_implicit != 0, style: evt_data.style }) }, YAML_SEQUENCE_START_EVENT => { let evt_data: &ffi::yaml_sequence_start_event_t = mem::transmute(&event.data); YamlEventSpec::YamlSequenceStartEvent(YamlSequenceParam { anchor: codecs::decode_c_str(evt_data.anchor), tag: codecs::decode_c_str(evt_data.tag), implicit: evt_data.implicit != 0, style: evt_data.style }) }, YAML_SEQUENCE_END_EVENT => YamlEventSpec::YamlSequenceEndEvent, YAML_MAPPING_START_EVENT => { let evt_data: &ffi::yaml_mapping_start_event_t = mem::transmute(&event.data); YamlEventSpec::YamlMappingStartEvent(YamlSequenceParam { anchor: codecs::decode_c_str(evt_data.anchor), tag: codecs::decode_c_str(evt_data.tag), implicit: evt_data.implicit != 0, style: evt_data.style }) }, YAML_MAPPING_END_EVENT => YamlEventSpec::YamlMappingEndEvent } } } yaml-0.3.0/src/ffi.rs010064426426055645743000000330131334127756100126500ustar0000000000000000pub use type_size::*; use libc::{c_char, c_uchar, c_int, c_void, size_t}; use parser::YamlIoParser; use emitter::YamlEmitter; #[allow(non_camel_case_types)] pub type yaml_char_t = c_uchar; #[allow(non_camel_case_types)] pub type yaml_read_handler_t = extern fn(data: *mut YamlIoParser, buffer: *mut u8, size: size_t, size_read: *mut size_t) -> c_int; #[allow(non_camel_case_types)] pub type yaml_write_handler_t = extern fn(data: *mut YamlEmitter, buffer: *const u8, size: size_t) -> c_int; #[repr(C)] #[allow(non_camel_case_types)] #[derive(Debug, PartialEq, Clone, Copy)] pub enum YamlErrorType { /** No error is produced. */ YAML_NO_ERROR, /** Cannot allocate or reallocate a block of memory. */ YAML_MEMORY_ERROR, /** Cannot read or decode the input stream. */ YAML_READER_ERROR, /** Cannot scan the input stream. */ YAML_SCANNER_ERROR, /** Cannot parse the input stream. */ YAML_PARSER_ERROR, /** Cannot compose a YAML document. */ YAML_COMPOSER_ERROR, /** Cannot write to the output stream. */ YAML_WRITER_ERROR, /** Cannot emit a YAML stream. */ YAML_EMITTER_ERROR } #[derive(Debug, PartialEq, Clone, Copy)] #[repr(C)] pub enum YamlSequenceStyle { /** Let the emitter choose the style. */ YamlAnySequenceStyle = 0, /** The block sequence style. */ YamlBlockSequenceStyle, /** The flow sequence style. */ YamlFlowSequenceStyle } #[derive(Debug, PartialEq, Clone, Copy)] #[repr(C)] pub enum YamlScalarStyle { /** Let the emitter choose the style. */ YamlAnyScalarStyle = 0, /** The plain scalar style. */ YamlPlainScalarStyle, /** The single-quoted scalar style. */ YamlSingleQuotedScalarStyle, /** The double-quoted scalar style. */ YamlDoubleQuotedScalarStyle, /** The literal scalar style. */ YamlLiteralScalarStyle, /** The folded scalar style. */ YamlFoldedScalarStyle } #[derive(Debug, PartialEq, Clone, Copy)] #[repr(C)] pub enum YamlEncoding { /** Let the parser choose the encoding. */ YamlAnyEncoding = 0, /** The default UTF-8 encoding. */ YamlUtf8Encoding, /** The UTF-16-LE encoding with BOM. */ YamlUtf16LeEncoding, /** The UTF-16-BE encoding with BOM. */ YamlUtf16BeEncoding } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_mark_t { pub index: size_t, pub line: size_t, pub column: size_t } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_buffer_t { pub start: *const yaml_char_t, pub end: *const yaml_char_t, pub pointer: *const yaml_char_t, pub last: *const yaml_char_t } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_queue_t { pub start: *const c_void, pub end: *const c_void, pub head: *const c_void, pub tail: *const c_void } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_stack_t { pub start: *const c_void, pub end: *const c_void, pub top: *const c_void } #[repr(C)] #[allow(non_camel_case_types)] #[derive(Clone, Copy)] pub enum yaml_node_type_t { /** An empty node. */ YAML_NO_NODE = 0, /** A scalar node. */ YAML_SCALAR_NODE, /** A sequence node. */ YAML_SEQUENCE_NODE, /** A mapping node. */ YAML_MAPPING_NODE } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_node_t { pub node_type: yaml_node_type_t, pub tag: *const yaml_char_t, pub data: yaml_node_data_t, pub start_mark: yaml_mark_t, pub end_mark: yaml_mark_t, } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_scalar_node_t { pub value: *const yaml_char_t, pub length: size_t, pub style: YamlScalarStyle } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_sequence_node_t { pub items: yaml_stack_t, pub style: YamlSequenceStyle } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_node_pair_t { pub key: c_int, pub value: c_int } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_document_t { pub nodes: yaml_stack_t, pub version_directive: *const yaml_version_directive_t, pub tag_directives: yaml_tag_directive_list_t, pub start_implicit: c_int, pub end_implicit: c_int, pub start_mark: yaml_mark_t, pub end_mark: yaml_mark_t, } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_parser_t { pub error: YamlErrorType, pub problem: *const c_char, pub problem_offset: size_t, pub problem_value: c_int, pub problem_mark: yaml_mark_t, pub context: *const c_char, pub context_mark: yaml_mark_t, pub read_handler: yaml_read_handler_t, pub read_handler_data: *const c_void, pub input: yaml_parser_input_t, pub eof: c_int, pub buffer: yaml_buffer_t, pub unread: size_t, pub raw_buffer: yaml_buffer_t, pub encoding: YamlEncoding, pub offset: size_t, pub mark: yaml_mark_t, pub stream_start_produced: c_int, pub stream_end_produced: c_int, pub flow_level: c_int, pub tokens: yaml_queue_t, pub tokens_parsed: size_t, pub token_available: c_int, pub indents: yaml_stack_t, pub indent: c_int, pub simple_key_allowed: c_int, pub simple_keys: yaml_stack_t, pub states: yaml_stack_t, pub parser_state: c_int, pub marks: yaml_stack_t, pub tag_directives: yaml_stack_t, pub aliases: yaml_stack_t, pub document: *const yaml_document_t, } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub enum yaml_break_t { /** Let the parser choose the break type. */ YAML_ANY_BREAK, /** Use CR for line breaks (Mac style). */ YAML_CR_BREAK, /** Use LN for line breaks (Unix style). */ YAML_LN_BREAK, /** Use CR LN for line breaks (DOS style). */ YAML_CRLN_BREAK } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_emitter_t { pub error: YamlErrorType, pub problem: *const c_char, pub write_handler: yaml_write_handler_t, pub write_handler_data: *const c_void, pub output: yaml_emitter_output_t, pub buffer: yaml_buffer_t, pub raw_buffer: yaml_buffer_t, pub encoding: YamlEncoding, pub canonical: c_int, pub best_indent: c_int, pub best_width: c_int, pub unicode: c_int, pub line_break: yaml_break_t, pub states: yaml_stack_t, pub state: c_int, pub events: yaml_queue_t, pub indents: yaml_stack_t, pub tag_directives: yaml_stack_t, pub indent: c_int, pub flow_level: c_int, pub root_context: c_int, pub sequence_context: c_int, pub mapping_context: c_int, pub simple_key_context: c_int, pub line: c_int, pub column: c_int, pub whitespace: c_int, pub indention: c_int, pub open_ended: c_int, pub anchor_data: yaml_emitter_anchor_data_t, pub tag_data: yaml_emitter_tag_data_t, pub scalar_data: yaml_emitter_scalar_data_t, pub opened: c_int, pub closed: c_int, pub anchors: *const c_void, pub last_anchor_id: c_int, pub document: *const yaml_document_t } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_emitter_anchor_data_t { pub anchor: *const yaml_char_t, pub anchor_length: size_t, pub alias: c_int } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_emitter_tag_data_t { pub handle: *const yaml_char_t, pub handle_length: size_t, pub suffix: *const yaml_char_t, pub suffix_length: size_t } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_emitter_scalar_data_t { pub value: *const yaml_char_t, pub length: size_t, pub multiline: c_int, pub flow_plain_allowed: c_int, pub block_plain_allowed: c_int, pub single_quoted_allowed: c_int, pub block_allowed: c_int, pub style: YamlScalarStyle, } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_event_t { pub event_type: yaml_event_type_t, pub data: yaml_event_data_t, pub start_mark: yaml_mark_t, pub end_mark: yaml_mark_t } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_stream_start_event_t { pub encoding: YamlEncoding } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_tag_directive_list_t { pub start: *const yaml_tag_directive_t, pub end: *const yaml_tag_directive_t, } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_document_start_event_t { pub version_directive: *const yaml_version_directive_t, pub tag_directives: yaml_tag_directive_list_t, pub implicit: c_int } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_document_end_event_t { pub implicit: c_int } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_alias_event_t { pub anchor: *const yaml_char_t } #[allow(non_camel_case_types)] pub struct yaml_sequence_start_event_t { pub anchor: *const yaml_char_t, pub tag: *const yaml_char_t, pub implicit: c_int, pub style: YamlSequenceStyle } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_mapping_start_event_t { pub anchor: *const yaml_char_t, pub tag: *const yaml_char_t, pub implicit: c_int, pub style: YamlSequenceStyle } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_scalar_event_t { pub anchor: *const yaml_char_t, pub tag: *const yaml_char_t, pub value: *const yaml_char_t, pub length: size_t, pub plain_implicit: c_int, pub quoted_implicit: c_int, pub style: YamlScalarStyle } impl yaml_event_t { pub unsafe fn delete(&mut self) { yaml_event_delete(self); } } #[derive(Clone, Copy)] #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_version_directive_t { pub major: c_int, pub minor: c_int } #[repr(C)] #[allow(non_camel_case_types)] pub struct yaml_tag_directive_t { pub handle: *const c_char, pub prefix: *const c_char } #[link(name = "yaml")] #[allow(improper_ctypes)] extern { pub fn yaml_get_version_string() -> *const c_char; pub fn yaml_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_void; pub fn yaml_event_delete(event: *mut yaml_event_t) -> c_void; pub fn yaml_document_initialize(document: *mut yaml_document_t, version_directive: *const yaml_version_directive_t, tag_directives_start: *const yaml_tag_directive_t, tag_directives_end: *const yaml_tag_directive_t, start_implicit: c_int, end_implicit: c_int) -> c_int; pub fn yaml_document_get_node(document: *const yaml_document_t, index: c_int) -> *const yaml_node_t; pub fn yaml_document_get_root_node(document: *const yaml_document_t) -> *const yaml_node_t; pub fn yaml_document_delete(document: *mut yaml_document_t) -> c_void; pub fn yaml_document_add_scalar(document: *mut yaml_document_t, tag: *const yaml_char_t, value: *const yaml_char_t, length: c_int, style: YamlScalarStyle) -> c_int; pub fn yaml_document_add_sequence(document: *mut yaml_document_t, tag: *const yaml_char_t, style: YamlSequenceStyle) -> c_int; pub fn yaml_document_add_mapping(document: *mut yaml_document_t, tag: *const yaml_char_t, style: YamlSequenceStyle) -> c_int; pub fn yaml_parser_initialize(parser: *mut yaml_parser_t) -> c_int; pub fn yaml_parser_set_encoding(parser: *mut yaml_parser_t, encoding: YamlEncoding) -> c_void; pub fn yaml_parser_delete(parser: *mut yaml_parser_t) -> c_void; pub fn yaml_parser_set_input_string(parser: *mut yaml_parser_t, input: *const yaml_char_t, size: size_t) -> c_void; pub fn yaml_parser_set_input(parser: *mut yaml_parser_t, handler: yaml_read_handler_t, data: *const c_void) -> c_void; pub fn yaml_parser_parse(parser: *mut yaml_parser_t, event: *mut yaml_event_t) -> c_int; pub fn yaml_parser_load(parser: *mut yaml_parser_t, document: *mut yaml_document_t) -> c_int; pub fn yaml_emitter_initialize(emitter: *mut yaml_emitter_t) -> c_int; pub fn yaml_emitter_emit(emitter: *mut yaml_emitter_t, event: *mut yaml_event_t) -> c_int; pub fn yaml_emitter_delete(emitter: *mut yaml_emitter_t) -> c_void; pub fn yaml_emitter_set_output(emitter: *mut yaml_emitter_t, handler: yaml_write_handler_t, data: *const c_void) -> c_void; pub fn yaml_emitter_flush(emitter: *mut yaml_emitter_t) -> c_int; pub fn yaml_stream_start_event_initialize(event: *mut yaml_event_t, encoding: YamlEncoding) -> c_int; pub fn yaml_stream_end_event_initialize(event: *mut yaml_event_t) -> c_int; pub fn yaml_document_start_event_initialize(event: *mut yaml_event_t, version_directive: *const yaml_version_directive_t, tag_directives_start: *const yaml_tag_directive_t, tag_directies_end: *const yaml_tag_directive_t, implicit: c_int) -> c_int; pub fn yaml_document_end_event_initialize(event: *mut yaml_event_t, implicit: c_int) -> c_int; pub fn yaml_alias_event_initialize(event: *mut yaml_event_t, anchor: *const yaml_char_t) -> c_int; pub fn yaml_scalar_event_initialize(event: *mut yaml_event_t, anchor: *const yaml_char_t, tag: *const yaml_char_t, value: *const yaml_char_t, length: c_int, plain_implicit: c_int, quoted_implicit: c_int, style: YamlScalarStyle) -> c_int; pub fn yaml_sequence_start_event_initialize(event: *mut yaml_event_t, anchor: *const yaml_char_t, tag: *const yaml_char_t, implicit: c_int, style: YamlSequenceStyle) -> c_int; pub fn yaml_sequence_end_event_initialize(event: *mut yaml_event_t) -> c_int; pub fn yaml_mapping_start_event_initialize(event: *mut yaml_event_t, anchor: *const yaml_char_t, tag: *const yaml_char_t, implicit: c_int, style: YamlSequenceStyle) -> c_int; pub fn yaml_mapping_end_event_initialize(event: *mut yaml_event_t) -> c_int; } yaml-0.3.0/src/lib.rs010064426426055645743000000070321334130201500126330ustar0000000000000000#![crate_name = "yaml"] #![crate_type = "lib"] extern crate libc; extern crate regex; use std::str; use std::ffi::CStr; use std::io::Read; use parser::YamlParser; use constructor::{YamlStandardData, YamlStandardConstructor, YamlConstructor}; use error::YamlError; pub mod ffi; pub mod error; pub mod event; pub mod parser; pub mod emitter; pub mod document; pub mod codecs; pub mod constructor; mod type_size; pub fn version_string() -> String { unsafe { str::from_utf8(CStr::from_ptr(ffi::yaml_get_version_string()).to_bytes()).unwrap().to_string() } } pub fn version() -> (isize, isize, isize) { let mut c_major: libc::c_int = 0; let mut c_minor: libc::c_int = 0; let mut c_patch: libc::c_int = 0; unsafe { ffi::yaml_get_version( &mut c_major as *mut libc::c_int, &mut c_minor as *mut libc::c_int, &mut c_patch as *mut libc::c_int ); } (c_major as isize, c_minor as isize, c_patch as isize) } pub fn parse_bytes_utf8(bytes: &[u8]) -> Result, YamlError> { parse_bytes(bytes, ffi::YamlEncoding::YamlUtf8Encoding) } pub fn parse_bytes(bytes: &[u8], encoding: ffi::YamlEncoding) -> Result, YamlError> { let parser = parser::YamlByteParser::init(bytes, encoding); let ctor = YamlStandardConstructor::new(); parser.load().map(|doc_res| doc_res.and_then(|doc| ctor.construct(doc.root().unwrap())) ).collect() } pub fn parse_io_utf8(reader: &mut Read) -> Result, YamlError> { parse_io(reader, ffi::YamlEncoding::YamlUtf8Encoding) } pub fn parse_io(reader: &mut Read, encoding: ffi::YamlEncoding) -> Result, YamlError> { let parser = parser::YamlIoParser::init(reader, encoding); let ctor = YamlStandardConstructor::new(); parser.load().map(|doc_res| doc_res.and_then(|doc| ctor.construct(doc.root().unwrap())) ).collect() } #[cfg(test)] mod test { use std::mem; use std::io::BufReader; use constructor::YamlStandardData::*; #[test] fn test_version_string() { let vsn = super::version_string(); assert!("0.1.4".to_string() <= vsn && vsn < "0.2".to_string()) } #[test] fn test_version() { let vsn = super::version(); assert!((0, 1, 4) <= vsn && vsn < (0, 2, 0)) } #[test] fn test_event_size() { assert_eq!(super::type_size::YAML_EVENT_T_SIZE, mem::size_of::()) } #[test] fn test_parser_size() { assert_eq!(super::type_size::YAML_PARSER_T_SIZE, mem::size_of::()) } #[test] fn test_emitter_size() { assert_eq!(super::type_size::YAML_EMITTER_T_SIZE, mem::size_of::()) } #[test] fn test_document_size() { assert_eq!(super::type_size::YAML_DOCUMENT_T_SIZE, mem::size_of::()) } #[test] fn test_node_size() { assert_eq!(super::type_size::YAML_NODE_T_SIZE, mem::size_of::()) } #[test] fn test_parse_bytes() { let data = "[1, 2, 3]"; assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_bytes_utf8(data.as_bytes())) } #[test] fn test_parse_io() { let data = "[1, 2, 3]"; let mut reader = BufReader::new(data.as_bytes()); assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_io_utf8(&mut reader)) } } yaml-0.3.0/src/parser.rs010064426426055645743000000326421334127756100134070ustar0000000000000000use libc; use ffi; use error::{YamlError, YamlErrorContext, YamlMark}; use event::{YamlEvent, YamlEventSpec}; use document::{YamlDocument}; use codecs; use std::mem; use std::io; use std::io::Read; use std::slice; use std::marker::PhantomData; pub struct YamlEventStream

{ parser: Box

, } impl Iterator for YamlEventStream

{ type Item = Result; fn next(&mut self) -> Option> { unsafe { match self.parser.parse_event() { Some(evt) => match evt.spec { YamlEventSpec::YamlNoEvent => None, _ => Some(Ok(evt)) }, None => Some(Err(self.parser.get_error())) } } } } pub struct YamlDocumentStream

{ parser: Box

, } impl Iterator for YamlDocumentStream

{ type Item = Result, YamlError>; fn next(&mut self) -> Option, YamlError>> { unsafe { match YamlDocument::parser_load(&mut self.parser.base_parser_ref().parser_mem) { Some(doc) => if doc.is_empty() { None } else { Some(Ok(doc)) }, None => Some(Err(self.parser.get_error())) } } } } pub struct InternalEvent { event_mem: ffi::yaml_event_t } impl Drop for InternalEvent { fn drop(&mut self) { unsafe { self.event_mem.delete() } } } pub trait YamlParser: Sized { unsafe fn base_parser_ref<'r>(&'r mut self) -> &'r mut YamlBaseParser; unsafe fn get_error(&mut self) -> YamlError; unsafe fn parse_event(&mut self) -> Option { let mut event = InternalEvent { event_mem: mem::uninitialized() }; if !self.base_parser_ref().parse(&mut event.event_mem) { None } else { Some(YamlEvent::load(&event.event_mem)) } } fn parse(self: Box) -> YamlEventStream { YamlEventStream { parser: self, } } fn load(self: Box) -> YamlDocumentStream { YamlDocumentStream { parser: self, } } } extern fn handle_reader_cb(data: *mut YamlIoParser, buffer: *mut u8, size: libc::size_t, size_read: *mut libc::size_t) -> libc::c_int { unsafe { let buf = slice::from_raw_parts_mut(buffer, size as usize); let parser = &mut *data; match parser.reader.read(buf) { Ok(size) => { *size_read = size as libc::size_t; return 1; }, Err(err) => { parser.io_error = Some(err); return 0; } } } } pub struct YamlBaseParser { parser_mem: ffi::yaml_parser_t, } impl YamlBaseParser { unsafe fn new() -> YamlBaseParser { YamlBaseParser { parser_mem: mem::uninitialized() } } unsafe fn initialize(&mut self) -> bool { ffi::yaml_parser_initialize(&mut self.parser_mem) != 0 } unsafe fn set_input_string(&mut self, input: *const u8, size: usize) { ffi::yaml_parser_set_input_string(&mut self.parser_mem, input, size as libc::size_t); } unsafe fn parse(&mut self, event: &mut ffi::yaml_event_t) -> bool { ffi::yaml_parser_parse(&mut self.parser_mem, event) != 0 } unsafe fn build_error(&self) -> YamlError { let context = YamlErrorContext { byte_offset: self.parser_mem.problem_offset as usize, problem_mark: YamlMark::conv(&self.parser_mem.problem_mark), context: codecs::decode_c_str(self.parser_mem.context as *const ffi::yaml_char_t), context_mark: YamlMark::conv(&self.parser_mem.context_mark), }; YamlError { kind: self.parser_mem.error, problem: codecs::decode_c_str(self.parser_mem.problem as *const ffi::yaml_char_t), io_error: None, context: Some(context) } } } impl Drop for YamlBaseParser { fn drop(&mut self) { unsafe { ffi::yaml_parser_delete(&mut self.parser_mem); } } } pub struct YamlByteParser<'r> { base_parser: YamlBaseParser, data: PhantomData<&'r [u8]> } impl<'r> YamlParser for YamlByteParser<'r> { unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser { &mut self.base_parser } unsafe fn get_error(&mut self) -> YamlError { self.base_parser.build_error() } } impl<'r> YamlByteParser<'r> { pub fn init(bytes: &'r [u8], encoding: ffi::YamlEncoding) -> Box> { unsafe { let mut parser = Box::new(YamlByteParser { base_parser: YamlBaseParser::new(), data: PhantomData }); if !parser.base_parser.initialize() { panic!("failed to initialize yaml_parser_t"); } ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding); parser.base_parser.set_input_string(bytes.as_ptr(), bytes.len()); parser } } } pub struct YamlIoParser<'r> { base_parser: YamlBaseParser, reader: &'r mut (Read+'r), io_error: Option, } impl<'r> YamlParser for YamlIoParser<'r> { unsafe fn base_parser_ref<'a>(&'a mut self) -> &'a mut YamlBaseParser { &mut self.base_parser } unsafe fn get_error(&mut self) -> YamlError { let mut error = self.base_parser.build_error(); mem::swap(&mut (error.io_error), &mut (self.io_error)); return error; } } impl<'r> YamlIoParser<'r> { pub fn init<'a>(reader: &'a mut Read, encoding: ffi::YamlEncoding) -> Box> { unsafe { let mut parser = Box::new(YamlIoParser { base_parser: YamlBaseParser::new(), reader: reader, io_error: None }); if !parser.base_parser.initialize() { panic!("failed to initialize yaml_parser_t"); } ffi::yaml_parser_set_encoding(&mut parser.base_parser.parser_mem, encoding); ffi::yaml_parser_set_input(&mut parser.base_parser.parser_mem, handle_reader_cb, mem::transmute(&mut *parser)); parser } } } #[cfg(test)] mod test { use event::{YamlEventSpec, YamlSequenceParam, YamlScalarParam}; use event::YamlEventSpec::*; use document::{YamlDocument, YamlNode}; use parser; use parser::YamlParser; use error::YamlError; use ffi::YamlErrorType; use ffi::YamlEncoding::*; use ffi::YamlScalarStyle::*; use ffi::YamlSequenceStyle::*; use std::io::BufReader; #[test] fn test_byte_parser() { let data = "[1, 2, 3]"; let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); let expected = Ok(vec![ YamlStreamStartEvent(YamlUtf8Encoding), YamlDocumentStartEvent(None, vec![], true), YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlSequenceEndEvent, YamlDocumentEndEvent(true), YamlStreamEndEvent ]); let stream: Result, YamlError> = parser.parse().map(|res| res.map(|evt| evt.spec)).collect(); assert_eq!(expected, stream); } #[test] fn test_io_parser() { let data = "[1, 2, 3]"; let mut reader = BufReader::new(data.as_bytes()); let parser = parser::YamlIoParser::init(&mut reader, YamlUtf8Encoding); let expected = Ok(vec![ YamlStreamStartEvent(YamlUtf8Encoding), YamlDocumentStartEvent(None, vec![], true), YamlSequenceStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "3".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlSequenceEndEvent, YamlDocumentEndEvent(true), YamlStreamEndEvent ]); let stream: Result, YamlError> = parser.parse().map(|res| res.map(|evt| evt.spec)).collect(); assert_eq!(expected, stream); } #[test] fn test_byte_parser_mapping() { let data = "{\"a\": 1, \"b\":2}"; let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); let expected = Ok(vec![ YamlStreamStartEvent(YamlUtf8Encoding), YamlDocumentStartEvent(None, vec![], true), YamlMappingStartEvent(YamlSequenceParam{anchor: None, tag: None, implicit: true, style: YamlFlowSequenceStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "a".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "1".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "b".to_string(), plain_implicit: false, quoted_implicit: true, style: YamlDoubleQuotedScalarStyle}), YamlScalarEvent(YamlScalarParam{anchor: None, tag: None, value: "2".to_string(), plain_implicit: true, quoted_implicit: false, style: YamlPlainScalarStyle}), YamlMappingEndEvent, YamlDocumentEndEvent(true), YamlStreamEndEvent ]); let stream: Result, YamlError> = parser.parse().map(|res| res.map(|evt| evt.spec)).collect(); assert_eq!(expected, stream); } #[test] fn test_parser_error() { let data = "\"ab"; let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); let mut stream = parser.parse(); let stream_start = stream.next(); match stream_start { Some(Ok(evt)) => assert_eq!(YamlStreamStartEvent(YamlUtf8Encoding), evt.spec), res => panic!("unexpected result: {:?}", res) } let stream_err = stream.next(); match stream_err { Some(Err(err)) => assert_eq!(YamlErrorType::YAML_SCANNER_ERROR, err.kind), evt => panic!("unexpected result: {:?}", evt), } } #[test] fn test_document() { let data = "[1, 2, 3]"; let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); let docs_res:Result>, YamlError> = parser.load().collect(); match docs_res { Err(e) => panic!("unexpected result: {:?}", e), Ok(docs) => match docs[..].first().and_then(|doc| doc.root()) { Some(YamlNode::YamlSequenceNode(seq)) => { let values:Vec = seq.values().map(|node| { match node { YamlNode::YamlScalarNode(scalar) => scalar.get_value(), _ => panic!("unexpected scalar") } }).collect(); assert_eq!(vec!["1".to_string(), "2".to_string(), "3".to_string()], values) }, _ => panic!("unexpected result") } } } #[test] fn test_mapping_document() { let data = "{\"a\": 1, \"b\": 2}"; let parser = parser::YamlByteParser::init(data.as_bytes(), YamlUtf8Encoding); let docs_res:Result>, YamlError> = parser.load().collect(); match docs_res { Err(e) => panic!("unexpected result: {:?}", e), Ok(docs) => match docs[..].first().and_then(|doc| doc.root()) { Some(YamlNode::YamlMappingNode(seq)) => { let values:Vec<(String, String)> = seq.pairs().map(|(key, value)| { ( match key { YamlNode::YamlScalarNode(scalar) => scalar.get_value(), _ => panic!("unexpected scalar") }, match value { YamlNode::YamlScalarNode(scalar) => scalar.get_value(), _ => panic!("unexpected scalar") } ) }).collect(); assert_eq!(vec![("a".to_string(), "1".to_string()), ("b".to_string(), "2".to_string())], values) }, _ => panic!("unexpected result") } } } } yaml-0.3.0/src/type_size.rs010064426426055645743000000000641334130203000140730ustar0000000000000000include!(concat!(env!("OUT_DIR"), "/type_size.rs"));yaml-0.3.0/tests/io_error_test.rs010064426426055645743000000031411273207047100153270ustar0000000000000000extern crate yaml; use yaml::error::YamlError; use yaml::emitter::YamlEmitter; use yaml::ffi::{YamlEncoding, YamlScalarStyle}; use std::error::Error; use std::io; use std::io::{Read, Write}; struct MockRW { _data: () } impl MockRW { pub fn new() -> MockRW { MockRW { _data: () } } } impl Read for MockRW { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "")) } } impl Write for MockRW { fn write(&mut self, _buf: &[u8]) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "")) } fn flush(&mut self) -> io::Result<()> { Err(io::Error::new(io::ErrorKind::Other, "")) } } #[test] fn error_cause_test_read() { let mut mock_reader = MockRW::new(); match yaml::parse_io_utf8(&mut mock_reader) { Ok(_) => panic!("Should return an error"), Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string())) } } fn write_to_bad_stream() -> Result<(), YamlError> { let mut mock_writer = MockRW::new(); let mut emitter = YamlEmitter::init(&mut mock_writer); try!(emitter.emit_stream(YamlEncoding::YamlUtf8Encoding, |stream| stream.emit_document(None, &[], true, |doc| { doc.emit_scalar_event(None, None, "a", true, false, YamlScalarStyle::YamlPlainScalarStyle) }) )); emitter.flush() } #[test] fn error_cause_test_write() { match write_to_bad_stream() { Ok(_) => panic!("Should return an error"), Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string())) } } yaml-0.3.0/tests/source/alias.yml010064426426055645743000000001771273207047100152240ustar0000000000000000--- hr: - Mark McGwire # Following node labeled SS - &SS Sammy Sosa rbi: - *SS # Subsequent occurrence - Ken Griffey yaml-0.3.0/tests/source/ball_clubs.yml010064426426055645743000000002051273207047100162250ustar0000000000000000american: - Boston Red Sox - Detroit Tigers - New York Yankees national: - New York Mets - Chicago Cubs - Atlanta Braves yaml-0.3.0/tests/source/ball_players.yml010064426426055645743000000000521273207047100165740ustar0000000000000000- Mark McGwire - Sammy Sosa - Ken Griffey yaml-0.3.0/tests/source/block_literal.yml010064426426055645743000000000541273207047100167330ustar0000000000000000# ASCII Art --- | \//||\/|| // || ||__ yaml-0.3.0/tests/source/complex_key.yml010064426426055645743000000002161273207047100164440ustar0000000000000000? - Detroit Tigers - Chicago Cubs : - 2001-07-23 ? [ New York Yankees, Atlanta Braves ] : [ 2001-07-02, 2001-08-12, 2001-08-14 ] yaml-0.3.0/tests/source/csv.yml010064426426055645743000000000771273207047100147250ustar0000000000000000- [name , hr] - [Mark McGwire, 65] - [Sammy Sosa , 63] yaml-0.3.0/tests/source/map_map.yml010064426426055645743000000000641273207047100155400ustar0000000000000000Mark McGwire: {hr: 65} Sammy Sosa: { hr: 63 } yaml-0.3.0/tests/source/multi_line_scalar.yml010064426426055645743000000001351273207047100176130ustar0000000000000000plain: This unquoted scalar spans many lines. quoted: "So does this quoted scalar.\n" yaml-0.3.0/tests/source/multiple_player_stat.yml010064426426055645743000000001021273207047100203610ustar0000000000000000- name: Mark McGwire hr: 65 - name: Sammy Sosa hr: 63 yaml-0.3.0/tests/source/plain_scalar.yml010064426426055645743000000000751273207047100165600ustar0000000000000000--- Mark McGwire's year was crippled by a knee injury. yaml-0.3.0/tests/source/player_stat.yml010064426426055645743000000001311273207047100164500ustar0000000000000000hr: 65 # Home runs avg: 0.278 # Batting average rbi: 147 # Runs Batted In yaml-0.3.0/tests/source/quoted_scalar.yml010064426426055645743000000002611273207047100167530ustar0000000000000000unicode: "Sosa did fine.\u263A" control: "\b1998\t1999\t2000\n" hexesc: "\x13\x10 is \r\n" single: '"Howdy!" he cried.' quoted: ' # not a ''comment''.' tie-fighter: '|\-*-/|' yaml-0.3.0/tests/source/utf16be.yml010064426426055645743000000000421273207047100153760ustar0000000000000000þÿ["Hello", "NuL"] yaml-0.3.0/tests/source/utf16le.yml010064426426055645743000000000421273207047100154100ustar0000000000000000ÿþ["Hello", "NLu"] yaml-0.3.0/tests/yaml_spec_test.rs010064426426055645743000000113231273207047100154640ustar0000000000000000// Allow unstable items until Rust hits 1.0 extern crate yaml; use yaml::constructor::YamlStandardData; use yaml::ffi::YamlEncoding; use std::io::Cursor; macro_rules! test_utf8{ ($filename: expr, $expected: expr) => ( test_file!(yaml::ffi::YamlEncoding::YamlUtf8Encoding, $filename, $expected) ) } macro_rules! test_file{ ($encoding: expr, $filename: expr, $expected: expr) => ( { let data: &[u8] = include_bytes!($filename); let mut reader = Cursor::new(data); match yaml::parse_io(&mut reader, $encoding) { Ok(docs) => if docs.len() == 1 { assert_eq!(docs[..].first().unwrap(), &$expected) } else { panic!("too many number of documents: {:?}", docs) }, Err(e) => panic!("parse failure: {:?}", e) } } ) } macro_rules! ystr{ ($e: expr) => ( YamlStandardData::YamlString($e.to_string()) ) } macro_rules! yint{ ($e: expr) => ( YamlStandardData::YamlInteger($e) ) } macro_rules! yfloat{ ($e: expr) => ( YamlStandardData::YamlFloat($e) ) } macro_rules! yseq{ ($($e:expr),*) => ( YamlStandardData::YamlSequence(vec![$(($e),)*]) ) } macro_rules! ymap{ ($($k:expr => $v:expr),*) => ( YamlStandardData::YamlMapping(vec![$((ystr!($k), $v),)*]) ) } macro_rules! y_cmp_map{ ($($k:expr => $v:expr),*) => ( YamlStandardData::YamlMapping(vec![$(($k, $v),)*]) ) } #[test] fn sequence_of_scalars() { test_utf8!("source/ball_players.yml", yseq![ystr!("Mark McGwire"), ystr!("Sammy Sosa"), ystr!("Ken Griffey")]); } #[test] fn scalar_mappings() { test_utf8!("source/player_stat.yml", ymap!{ "hr" => yint!(65), "avg" => yfloat!(0.278), "rbi" => yint!(147) }) } #[test] fn maps_of_sequences() { test_utf8!("source/ball_clubs.yml", ymap!{ "american" => yseq![ystr!("Boston Red Sox"), ystr!("Detroit Tigers"), ystr!("New York Yankees")], "national" => yseq![ystr!("New York Mets"), ystr!("Chicago Cubs"), ystr!("Atlanta Braves")] }) } #[test] fn sequence_of_maps() { test_utf8!("source/multiple_player_stat.yml", yseq![ ymap!{ "name" => ystr!("Mark McGwire"), "hr" => yint!(65) }, ymap!{ "name" => ystr!("Sammy Sosa"), "hr" => yint!(63) } ]) } #[test] fn sequence_of_sequences() { test_utf8!("source/csv.yml", yseq![ yseq![ystr!("name"), ystr!("hr")], yseq![ystr!("Mark McGwire"), yint!(65)], yseq![ystr!("Sammy Sosa"), yint!(63)] ]) } #[test] fn mapping_of_mappings() { test_utf8!("source/map_map.yml", ymap!{ "Mark McGwire" => ymap!{ "hr" => yint!(65) }, "Sammy Sosa" => ymap!{ "hr" => yint!(63) } }) } #[test] fn alias() { test_utf8!("source/alias.yml", ymap!{ "hr" => yseq![ystr!("Mark McGwire"), ystr!("Sammy Sosa")], "rbi" => yseq![ystr!("Sammy Sosa"), ystr!("Ken Griffey")] }) } #[test] fn complex_keys() { test_utf8!("source/complex_key.yml", y_cmp_map!{ yseq![ystr!("Detroit Tigers"), ystr!("Chicago Cubs")] => yseq![ystr!("2001-07-23")], yseq![ystr!("New York Yankees"), ystr!("Atlanta Braves")] => yseq![ystr!("2001-07-02"), ystr!("2001-08-12"), ystr!("2001-08-14")] }) } #[test] fn block_literal() { test_utf8!("source/block_literal.yml", ystr!("\\//||\\/||\n// || ||__\n")) } #[test] fn plain_scalar() { test_utf8!("source/plain_scalar.yml", ystr!("Mark McGwire's year was crippled by a knee injury.")) } #[test] fn quoted_scalar() { test_utf8!("source/quoted_scalar.yml", ymap!{ "unicode" => ystr!("Sosa did fine.\u{263A}"), "control" => ystr!("\x081998\t1999\t2000\n"), "hexesc" => ystr!("\x13\x10 is \r\n"), "single" => ystr!(r#""Howdy!" he cried."#), "quoted" => ystr!(" # not a 'comment'."), "tie-fighter" => ystr!(r"|\-*-/|") }) } #[test] fn multi_line_scalar() { test_utf8!("source/multi_line_scalar.yml", ymap!{ "plain" => ystr!("This unquoted scalar spans many lines."), "quoted" => ystr!("So does this quoted scalar.\n") }) } #[test] fn utf16le() { test_file!(YamlEncoding::YamlUtf16LeEncoding, "source/utf16le.yml", yseq![ystr!("Hello"), ystr!("世界")] ) } #[test] fn utf16be() { test_file!(YamlEncoding::YamlUtf16BeEncoding, "source/utf16be.yml", yseq![ystr!("Hello"), ystr!("世界")] ) }