Part 5: parse edn::Value::Uuid.

This commit is contained in:
Richard Newman 2017-04-26 15:39:44 -07:00
parent 58a310a6e1
commit ab3600e288
6 changed files with 62 additions and 11 deletions

View file

@ -15,6 +15,7 @@ itertools = "0.5.9"
num = "0.1.35"
ordered-float = "0.4.0"
pretty = "0.2.0"
uuid = "0.5.0"
[build-dependencies]
peg = "0.5.1"

View file

@ -16,6 +16,7 @@ use std::f64::{NAN, INFINITY, NEG_INFINITY};
use num::BigInt;
use ordered_float::OrderedFloat;
use uuid::Uuid;
use types::{SpannedValue, Span, ValueAndSpan};
@ -142,6 +143,19 @@ pub text -> ValueAndSpan =
}
}
pub uuid_string -> Uuid =
"\"" u:$( [a-f0-9]*<8> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<12> ) "\"" {
Uuid::parse_str(u).expect("this is a valid UUID string")
}
pub uuid -> ValueAndSpan =
start:#position "#uuid" whitespace+ u:(uuid_string) end:#position {
ValueAndSpan {
inner: SpannedValue::Uuid(u),
span: Span::new(start, end)
}
}
namespace_divider = "."
namespace_separator = "/"
@ -220,7 +234,7 @@ pub map -> ValueAndSpan =
// It's important that float comes before integer or the parser assumes that
// floats are integers and fails to parse
pub value -> ValueAndSpan =
__ v:(nil / nan / infinity / boolean / float / octalinteger / hexinteger / basedinteger / bigint / integer / text / keyword / symbol / list / vector / map / set) __ {
__ v:(nil / nan / infinity / boolean / float / octalinteger / hexinteger / basedinteger / uuid / bigint / integer / text / keyword / symbol / list / vector / map / set) __ {
v
}

View file

@ -12,6 +12,7 @@ extern crate itertools;
extern crate num;
extern crate ordered_float;
extern crate pretty;
extern crate uuid;
pub mod symbols;
pub mod types;
@ -23,8 +24,12 @@ pub mod parse {
include!(concat!(env!("OUT_DIR"), "/edn.rs"));
}
// Re-export the types we use.
pub use num::BigInt;
pub use ordered_float::OrderedFloat;
pub use uuid::Uuid;
// Export from our modules.
pub use parse::ParseError;
pub use types::{Span, SpannedValue, Value, ValueAndSpan};
pub use symbols::{Keyword, NamespacedKeyword, PlainSymbol, NamespacedSymbol};

View file

@ -69,6 +69,7 @@ impl Value {
Value::NamespacedKeyword(ref v) => pp.text(":").append(v.namespace.as_ref()).append("/").append(v.name.as_ref()),
Value::Keyword(ref v) => pp.text(":").append(v.0.as_ref()),
Value::Text(ref v) => pp.text("\"").append(v.as_ref()).append("\""),
Value::Uuid(ref u) => pp.text("#uuid \"").append(u.hyphenated().to_string()).append("\""),
_ => pp.text(self.to_string())
}
}

View file

@ -15,9 +15,11 @@ use std::cmp::{Ordering, Ord, PartialOrd};
use std::fmt::{Display, Formatter};
use std::f64;
use symbols;
use num::BigInt;
use ordered_float::OrderedFloat;
use uuid::Uuid;
use symbols;
/// Value represents one of the allowed values in an EDN string.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
@ -28,6 +30,7 @@ pub enum Value {
BigInteger(BigInt),
Float(OrderedFloat<f64>),
Text(String),
Uuid(Uuid),
PlainSymbol(symbols::PlainSymbol),
NamespacedSymbol(symbols::NamespacedSymbol),
Keyword(symbols::Keyword),
@ -55,6 +58,7 @@ pub enum SpannedValue {
BigInteger(BigInt),
Float(OrderedFloat<f64>),
Text(String),
Uuid(Uuid),
PlainSymbol(symbols::PlainSymbol),
NamespacedSymbol(symbols::NamespacedSymbol),
Keyword(symbols::Keyword),
@ -126,6 +130,7 @@ impl From<SpannedValue> for Value {
SpannedValue::BigInteger(v) => Value::BigInteger(v),
SpannedValue::Float(v) => Value::Float(v),
SpannedValue::Text(v) => Value::Text(v),
SpannedValue::Uuid(v) => Value::Uuid(v),
SpannedValue::PlainSymbol(v) => Value::PlainSymbol(v),
SpannedValue::NamespacedSymbol(v) => Value::NamespacedSymbol(v),
SpannedValue::Keyword(v) => Value::Keyword(v),
@ -271,6 +276,7 @@ macro_rules! def_common_value_methods {
def_is!(is_big_integer, $t::BigInteger(_));
def_is!(is_float, $t::Float(_));
def_is!(is_text, $t::Text(_));
def_is!(is_uuid, $t::Uuid(_));
def_is!(is_symbol, $t::PlainSymbol(_));
def_is!(is_namespaced_symbol, $t::NamespacedSymbol(_));
def_is!(is_keyword, $t::Keyword(_));
@ -293,6 +299,7 @@ macro_rules! def_common_value_methods {
def_as_ref!(as_big_integer, $t::BigInteger, BigInt);
def_as_ref!(as_ordered_float, $t::Float, OrderedFloat<f64>);
def_as_ref!(as_text, $t::Text, String);
def_as_ref!(as_uuid, $t::Uuid, Uuid);
def_as_ref!(as_symbol, $t::PlainSymbol, symbols::PlainSymbol);
def_as_ref!(as_namespaced_symbol, $t::NamespacedSymbol, symbols::NamespacedSymbol);
def_as_ref!(as_keyword, $t::Keyword, symbols::Keyword);
@ -308,6 +315,7 @@ macro_rules! def_common_value_methods {
def_into!(into_ordered_float, $t::Float, OrderedFloat<f64>,);
def_into!(into_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
def_into!(into_text, $t::Text, String,);
def_into!(into_uuid, $t::Uuid, Uuid,);
def_into!(into_symbol, $t::PlainSymbol, symbols::PlainSymbol,);
def_into!(into_namespaced_symbol, $t::NamespacedSymbol, symbols::NamespacedSymbol,);
def_into!(into_keyword, $t::Keyword, symbols::Keyword,);
@ -337,14 +345,15 @@ macro_rules! def_common_value_methods {
$t::BigInteger(_) => 3,
$t::Float(_) => 4,
$t::Text(_) => 5,
$t::PlainSymbol(_) => 6,
$t::NamespacedSymbol(_) => 7,
$t::Keyword(_) => 8,
$t::NamespacedKeyword(_) => 9,
$t::Vector(_) => 10,
$t::List(_) => 11,
$t::Set(_) => 12,
$t::Map(_) => 13,
$t::Uuid(_) => 6,
$t::PlainSymbol(_) => 7,
$t::NamespacedSymbol(_) => 8,
$t::Keyword(_) => 9,
$t::NamespacedKeyword(_) => 10,
$t::Vector(_) => 11,
$t::List(_) => 12,
$t::Set(_) => 13,
$t::Map(_) => 14,
}
}
@ -356,6 +365,7 @@ macro_rules! def_common_value_methods {
$t::BigInteger(_) => false,
$t::Float(_) => false,
$t::Text(_) => false,
$t::Uuid(_) => false,
$t::PlainSymbol(_) => false,
$t::NamespacedSymbol(_) => false,
$t::Keyword(_) => false,
@ -392,6 +402,7 @@ macro_rules! def_common_value_ord {
(&$t::BigInteger(ref a), &$t::BigInteger(ref b)) => b.cmp(a),
(&$t::Float(ref a), &$t::Float(ref b)) => b.cmp(a),
(&$t::Text(ref a), &$t::Text(ref b)) => b.cmp(a),
(&$t::Uuid(ref a), &$t::Uuid(ref b)) => b.cmp(a),
(&$t::PlainSymbol(ref a), &$t::PlainSymbol(ref b)) => b.cmp(a),
(&$t::NamespacedSymbol(ref a), &$t::NamespacedSymbol(ref b)) => b.cmp(a),
(&$t::Keyword(ref a), &$t::Keyword(ref b)) => b.cmp(a),
@ -429,6 +440,7 @@ macro_rules! def_common_value_display {
}
// TODO: EDN escaping.
$t::Text(ref v) => write!($f, "\"{}\"", v),
$t::Uuid(ref u) => write!($f, "#uuid \"{}\"", u.hyphenated().to_string()),
$t::PlainSymbol(ref v) => v.fmt($f),
$t::NamespacedSymbol(ref v) => v.fmt($f),
$t::Keyword(ref v) => v.fmt($f),

View file

@ -11,6 +11,7 @@
extern crate edn;
extern crate num;
extern crate ordered_float;
extern crate uuid;
use std::collections::{BTreeSet, BTreeMap, LinkedList};
use std::iter::FromIterator;
@ -55,7 +56,7 @@ macro_rules! fn_parse_into_value {
}
// These look exactly like their `parse::foo` counterparts, but
// automatically convert the returned result into Value. Use `parse:foo`
// automatically convert the returned result into Value. Use `parse::foo`
// if you want the original ValueAndSpan instance.
fn_parse_into_value!(nil);
fn_parse_into_value!(nan);
@ -242,6 +243,23 @@ fn test_span_integer() {
});
}
#[test]
fn test_uuid() {
assert!(parse::uuid("#uuid \"z50e8400-e29b-41d4-a716-446655440000\"").is_err()); // Not hex.
assert!(parse::uuid("\"z50e8400-e29b-41d4-a716-446655440000\"").is_err()); // No tag.
assert!(parse::uuid("#uuid \"aaaaaaaae29b-41d4-a716-446655440000\"").is_err()); // Hyphens.
assert!(parse::uuid("#uuid \"aaaaaaaa-e29b-41d4-a716-446655440\"").is_err()); // Truncated.
assert!(parse::uuid("#uuid \"A50e8400-e29b-41d4-a716-446655440000\"").is_err()); // Capital.
let expected = uuid::Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")
.expect("valid UUID");
let actual = parse::uuid("#uuid \"550e8400-e29b-41d4-a716-446655440000\"")
.expect("parse success")
.inner
.into();
assert_eq!(self::Value::Uuid(expected), actual);
}
#[test]
fn test_bigint() {
use self::Value::*;