From 8f39d3399eb35d0e033a398617fe405b099aa8c9 Mon Sep 17 00:00:00 2001 From: Lori Holden Date: Tue, 10 Jan 2017 16:33:30 -0500 Subject: [PATCH] Add UUID type to contrib. --- contrib/Cargo.toml | 3 + contrib/src/lib.rs | 10 ++- contrib/src/uuid.rs | 148 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 contrib/src/uuid.rs diff --git a/contrib/Cargo.toml b/contrib/Cargo.toml index d348d77e..25cd44d4 100644 --- a/contrib/Cargo.toml +++ b/contrib/Cargo.toml @@ -24,6 +24,9 @@ lazy_static_macro = ["lazy_static"] rocket = { version = "0.1.4", path = "../lib/" } log = "^0.3" +# UUID dependencies. +uuid = { version = "^0.3", optional = true } + # JSON and templating dependencies. serde = { version = "^0.8", optional = true } serde_json = { version = "^0.8", optional = true } diff --git a/contrib/src/lib.rs b/contrib/src/lib.rs index b8600862..34b518b9 100644 --- a/contrib/src/lib.rs +++ b/contrib/src/lib.rs @@ -6,7 +6,8 @@ //! These libraries are always kept in-sync with the core Rocket library. They //! provide common, but not fundamental, abstractions to be used by Rocket //! applications. In particular, contributor libraries typically export types -//! that implement the `FromRequest` trait, `Responder` trait, or both. +//! implementing a combination of the `FromRequest`, `FromParam`, and +//! `Responder` traits. //! //! Each module in this library is held behind a feature flag, with the most //! common modules exposed by default. The present feature list is below, with @@ -15,6 +16,7 @@ //! * [json*](struct.JSON.html) //! * [handlebars_templates](struct.Template.html) //! * [tera_templates](struct.Template.html) +//! * [uuid](struct.UUID.html) //! //! The recommend way to include features from this crate via Cargo in your //! project is by adding a `[dependencies.rocket_contrib]` section to your @@ -45,6 +47,9 @@ mod json; #[cfg(feature = "templates")] mod templates; +#[cfg(feature = "uuid")] +mod uuid; + #[cfg(feature = "json")] pub use json::JSON; @@ -53,3 +58,6 @@ pub use json::SerdeError; #[cfg(feature = "templates")] pub use templates::Template; + +#[cfg(feature = "uuid")] +pub use uuid::{UUID, UuidParseError}; diff --git a/contrib/src/uuid.rs b/contrib/src/uuid.rs new file mode 100644 index 00000000..96ea9067 --- /dev/null +++ b/contrib/src/uuid.rs @@ -0,0 +1,148 @@ +extern crate uuid as uuid_ext; + +use std::fmt; +use std::str::FromStr; +use std::ops::Deref; +use rocket::request::FromParam; + +pub use self::uuid_ext::ParseError as UuidParseError; + +/// The UUID type, which implements `FromParam`. This type allows you to accept +/// values from the [Uuid](https://github.com/rust-lang-nursery/uuid) crate as +/// a dynamic parameter in your request handlers. +/// +/// # Usage +/// +/// To use, add the `uuid` feature to the `rocket_contrib` dependencies section +/// of your `Cargo.toml`: +/// +/// ```toml +/// [dependencies.rocket_contrib] +/// version = "*" +/// default-features = false +/// features = ["uuid"] +/// ``` +/// +/// With the `FromParam` trait, UUID allows you to use it directly as a target +/// of a dynamic parameter. +/// +/// ```rust,ignore +/// #[get("/users/")] +/// fn user(id: UUID) -> String { +/// format!("We found: {}", id) +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct UUID(uuid_ext::Uuid); + +impl UUID { + /// Consumes the UUID wrapper returning the underlying Uuid type. + /// + /// # Example + /// ```rust + /// # extern crate rocket_contrib; + /// # extern crate uuid; + /// # use rocket_contrib::UUID; + /// # use std::str::FromStr; + /// # use uuid::Uuid; + /// # fn main() { + /// let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; + /// let real_uuid = Uuid::from_str(uuid_str).unwrap(); + /// let my_inner_uuid = UUID::from_str(uuid_str).unwrap().into_inner(); + /// assert_eq!(real_uuid, my_inner_uuid); + /// # } + /// ``` + #[inline(always)] + pub fn into_inner(self) -> uuid_ext::Uuid { + self.0 + } +} + +impl fmt::Display for UUID { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl<'a> FromParam<'a> for UUID { + type Error = UuidParseError; + + /// A value is successfully parsed if the `str` is a properly formatted + /// UUID, otherwise `UuidParseError` is returned. + fn from_param(p: &'a str) -> Result { + p.parse() + } +} + +impl FromStr for UUID { + type Err = UuidParseError; + + fn from_str(s: &str) -> Result { + Ok(UUID(try!(s.parse()))) + } +} + +impl Deref for UUID { + type Target = uuid_ext::Uuid; + + fn deref<'a>(&'a self) -> &'a Self::Target { + &self.0 + } +} + +impl PartialEq for UUID { + fn eq(&self, other: &uuid_ext::Uuid) -> bool { + self.0.eq(other) + } +} + +#[cfg(test)] +mod test { + use super::uuid_ext; + use super::{UUID, UuidParseError}; + use super::FromParam; + use super::FromStr; + + #[test] + fn test_from_str() { + let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; + let uuid_wrapper = UUID::from_str(uuid_str).unwrap(); + assert_eq!(uuid_str, uuid_wrapper.to_string()) + } + + #[test] + fn test_from_param() { + let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; + let uuid_wrapper = UUID::from_param(uuid_str).unwrap(); + assert_eq!(uuid_str, uuid_wrapper.to_string()) + } + + #[test] + fn test_into_inner() { + let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; + let uuid_wrapper = UUID::from_param(uuid_str).unwrap(); + let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); + let inner_uuid: uuid_ext::Uuid = uuid_wrapper.into_inner(); + assert_eq!(real_uuid, inner_uuid) + } + + #[test] + fn test_partial_eq() { + let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; + let uuid_wrapper = UUID::from_param(uuid_str).unwrap(); + let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); + assert_eq!(uuid_wrapper, real_uuid) + } + + #[test] + fn test_from_param_invalid() { + let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2p"; + let uuid_result = UUID::from_param(uuid_str); + assert!(!uuid_result.is_ok()); + match uuid_result { + Err(e) => assert_eq!(e, UuidParseError::InvalidLength(37)), + _ => unreachable!(), + } + } +}