Rocket

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 9cb031a47d2a55d625565543a24d0f68f8f60d56
parent 28f2a33abdb7e1d6f462955e0bc08883e2eb68db
Author: Sergio Benitez <sb@sergio.bz>
Date:   Sat,  6 Oct 2018 17:24:11 -0700

Modularize contrib.

Diffstat:
Mcontrib/lib/Cargo.toml | 42+++++++++++++++++++++---------------------
Mcontrib/lib/src/databases.rs | 84+++++++++++++++++++++++++++++++++++--------------------------------------------
Mcontrib/lib/src/json.rs | 64++++++++++++++++++++++++++++++++++++++++------------------------
Mcontrib/lib/src/lib.rs | 73++++++++++++++-----------------------------------------------------------
Mcontrib/lib/src/msgpack.rs | 37++++++++++++++++---------------------
Acontrib/lib/src/serve.rs | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dcontrib/lib/src/static_files.rs | 242-------------------------------------------------------------------------------
Mcontrib/lib/src/templates/context.rs | 11+++++------
Mcontrib/lib/src/templates/engine.rs | 40++++++++++++++++++----------------------
Mcontrib/lib/src/templates/fairing.rs | 26++++++++++++--------------
Mcontrib/lib/src/templates/handlebars_templates.rs | 8+++-----
Mcontrib/lib/src/templates/metadata.rs | 52++++++++++++++++++++--------------------------------
Mcontrib/lib/src/templates/mod.rs | 44++++++++++++++++++++++++++------------------
Mcontrib/lib/src/templates/tera_templates.rs | 8+++-----
Mcontrib/lib/src/uuid.rs | 61+++++++++++++++++++++++++++++++++++--------------------------
Mcontrib/lib/tests/databases.rs | 2+-
Mcontrib/lib/tests/static_files.rs | 6+++---
Mcontrib/lib/tests/templates.rs | 7+++++--
Mexamples/cookies/src/main.rs | 4++--
Mexamples/cookies/src/tests.rs | 2+-
Mexamples/handlebars_templates/src/main.rs | 2+-
Mexamples/handlebars_templates/src/tests.rs | 2+-
Mexamples/json/src/main.rs | 7++++---
Mexamples/msgpack/src/main.rs | 2+-
Mexamples/session/src/main.rs | 2+-
Mexamples/static_files/src/main.rs | 2+-
Mexamples/tera_templates/src/main.rs | 2+-
Mexamples/tera_templates/src/tests.rs | 2+-
Mexamples/todo/Cargo.toml | 2+-
Mexamples/todo/src/main.rs | 2+-
Mexamples/uuid/src/main.rs | 8++++----
Mscripts/test.sh | 2+-
32 files changed, 522 insertions(+), 568 deletions(-)

diff --git a/contrib/lib/Cargo.toml b/contrib/lib/Cargo.toml @@ -11,46 +11,46 @@ keywords = ["rocket", "web", "framework", "contrib", "contributed"] license = "MIT/Apache-2.0" [features] -default = ["json", "static_files"] +# Internal use only. +templates = ["serde", "serde_json", "glob"] +databases = ["r2d2", "rocket_contrib_codegen/database_attribute"] + +# User-facing features. +default = ["json", "serve"] json = ["serde", "serde_json"] msgpack = ["serde", "rmp-serde"] tera_templates = ["tera", "templates"] handlebars_templates = ["handlebars", "templates"] -static_files = [] -# Internal use only. -templates = ["serde", "serde_json", "glob"] +serve = [] -# Database pooling features. -# Internal use only. -database_pool_codegen = ["rocket_contrib_codegen", "rocket_contrib_codegen/database_attribute"] -database_pool = ["r2d2", "database_pool_codegen"] -# External features. -diesel_postgres_pool = ["database_pool", "diesel/postgres", "diesel/r2d2"] -diesel_sqlite_pool = ["database_pool", "diesel/sqlite", "diesel/r2d2"] -diesel_mysql_pool = ["database_pool", "diesel/mysql", "diesel/r2d2"] -postgres_pool = ["database_pool", "postgres", "r2d2_postgres"] -mysql_pool = ["database_pool", "mysql", "r2d2_mysql"] -sqlite_pool = ["database_pool", "rusqlite", "r2d2_sqlite"] -cypher_pool = ["database_pool", "rusted_cypher", "r2d2_cypher"] -redis_pool = ["database_pool", "redis", "r2d2_redis"] +# The barage of user-facing database features. +diesel_sqlite_pool = ["databases", "diesel/sqlite", "diesel/r2d2"] +diesel_postgres_pool = ["databases", "diesel/postgres", "diesel/r2d2"] +diesel_mysql_pool = ["databases", "diesel/mysql", "diesel/r2d2"] +postgres_pool = ["databases", "postgres", "r2d2_postgres"] +mysql_pool = ["databases", "mysql", "r2d2_mysql"] +sqlite_pool = ["databases", "rusqlite", "r2d2_sqlite"] +cypher_pool = ["databases", "rusted_cypher", "r2d2_cypher"] +redis_pool = ["databases", "redis", "r2d2_redis"] [dependencies] +# Global dependencies. rocket = { version = "0.4.0-dev", path = "../../core/lib/" } log = "0.4" -# UUID dependencies. -uuid = { version = "0.7", optional = true } - # Serialization and templating dependencies. serde = { version = "1.0", optional = true } serde_json = { version = "1.0.26", optional = true } rmp-serde = { version = "^0.13", optional = true } -# Templating dependencies only. +# Templating dependencies. handlebars = { version = "1.0", optional = true } glob = { version = "0.2", optional = true } tera = { version = "0.11", optional = true } +# UUID dependencies. +uuid = { version = "0.7", optional = true } + # Database dependencies diesel = { version = "1.0", default-features = false, optional = true } postgres = { version = "0.15", optional = true } diff --git a/contrib/lib/src/databases.rs b/contrib/lib/src/databases.rs @@ -1,4 +1,3 @@ -#![doc(cfg(feature = "diesel_sqlite_pool"))] //! Traits, utilities, and a macro for easy database connection pooling. //! //! # Overview @@ -351,50 +350,41 @@ //! implementing the [`Poolable`] trait. See the documentation for [`Poolable`] //! for more details on how to implement it. //! -//! [`FromRequest`]: rocket::FromRequest -//! [request guards]: rocket::FromRequest +//! [`FromRequest`]: rocket::request::FromRequest +//! [request guards]: rocket::request::FromRequest //! [`Poolable`]: databases::Poolable pub extern crate r2d2; +#[cfg(any(feature = "diesel_sqlite_pool", + feature = "diesel_postgres_pool", + feature = "diesel_mysql_pool"))] +pub extern crate diesel; + use std::collections::BTreeMap; use std::fmt::{self, Display, Formatter}; use std::marker::{Send, Sized}; use rocket::config::{self, Value}; -#[doc(inline)] -pub use rocket_contrib_codegen::database; - use self::r2d2::ManageConnection; -#[cfg(any(feature = "diesel_sqlite_pool", feature = "diesel_postgres_pool", feature = "diesel_mysql_pool"))] -pub extern crate diesel; +#[doc(hidden)] pub use rocket_contrib_codegen::*; -#[cfg(feature = "postgres_pool")] -pub extern crate postgres; -#[cfg(feature = "postgres_pool")] -pub extern crate r2d2_postgres; +#[cfg(feature = "postgres_pool")] pub extern crate postgres; +#[cfg(feature = "postgres_pool")] pub extern crate r2d2_postgres; -#[cfg(feature = "mysql_pool")] -pub extern crate mysql; -#[cfg(feature = "mysql_pool")] -pub extern crate r2d2_mysql; +#[cfg(feature = "mysql_pool")] pub extern crate mysql; +#[cfg(feature = "mysql_pool")] pub extern crate r2d2_mysql; -#[cfg(feature = "sqlite_pool")] -pub extern crate rusqlite; -#[cfg(feature = "sqlite_pool")] -pub extern crate r2d2_sqlite; +#[cfg(feature = "sqlite_pool")] pub extern crate rusqlite; +#[cfg(feature = "sqlite_pool")] pub extern crate r2d2_sqlite; -#[cfg(feature = "cypher_pool")] -pub extern crate rusted_cypher; -#[cfg(feature = "cypher_pool")] -pub extern crate r2d2_cypher; +#[cfg(feature = "cypher_pool")] pub extern crate rusted_cypher; +#[cfg(feature = "cypher_pool")] pub extern crate r2d2_cypher; -#[cfg(feature = "redis_pool")] -pub extern crate redis; -#[cfg(feature = "redis_pool")] -pub extern crate r2d2_redis; +#[cfg(feature = "redis_pool")] pub extern crate redis; +#[cfg(feature = "redis_pool")] pub extern crate r2d2_redis; /// A structure representing a particular database configuration. /// @@ -447,14 +437,14 @@ pub enum DbError<T> { /// Error returned on invalid database configurations. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DatabaseConfigError { +pub enum ConfigError { /// The `databases` configuration key is missing or is empty. MissingTable, /// The requested database configuration key is missing from the active /// configuration. MissingKey, /// The configuration associated with the key isn't a - /// [Table](::rocket::config::Table). + /// [`Table`](::rocket::config::Table). MalformedConfiguration, /// The required `url` key is missing. MissingUrl, @@ -488,7 +478,7 @@ pub enum DatabaseConfigError { /// # /// # use std::{collections::BTreeMap, mem::drop}; /// # use rocket::{fairing::AdHoc, config::{Config, Environment, Value}}; -/// use rocket_contrib::databases::{database_config, DatabaseConfigError}; +/// use rocket_contrib::databases::{database_config, ConfigError}; /// /// # let mut databases = BTreeMap::new(); /// # @@ -517,7 +507,7 @@ pub enum DatabaseConfigError { /// assert_eq!(other_config.url, "mysql://root:root@localhost/database"); /// /// let error = database_config("invalid_db", rocket.config()).unwrap_err(); -/// assert_eq!(error, DatabaseConfigError::MissingKey); +/// assert_eq!(error, ConfigError::MissingKey); /// # } /// # /// # Ok(rocket) @@ -526,27 +516,27 @@ pub enum DatabaseConfigError { pub fn database_config<'a>( name: &str, from: &'a config::Config -) -> Result<DatabaseConfig<'a>, DatabaseConfigError> { +) -> Result<DatabaseConfig<'a>, ConfigError> { // Find the first `databases` config that's a table with a key of 'name' // equal to `name`. let connection_config = from.get_table("databases") - .map_err(|_| DatabaseConfigError::MissingTable)? + .map_err(|_| ConfigError::MissingTable)? .get(name) - .ok_or(DatabaseConfigError::MissingKey)? + .ok_or(ConfigError::MissingKey)? .as_table() - .ok_or(DatabaseConfigError::MalformedConfiguration)?; + .ok_or(ConfigError::MalformedConfiguration)?; let maybe_url = connection_config.get("url") - .ok_or(DatabaseConfigError::MissingUrl)?; + .ok_or(ConfigError::MissingUrl)?; - let url = maybe_url.as_str().ok_or(DatabaseConfigError::MalformedUrl)?; + let url = maybe_url.as_str().ok_or(ConfigError::MalformedUrl)?; let pool_size = connection_config.get("pool_size") .and_then(Value::as_integer) .unwrap_or(from.workers as i64); if pool_size < 1 || pool_size > u32::max_value() as i64 { - return Err(DatabaseConfigError::InvalidPoolSize(pool_size)); + return Err(ConfigError::InvalidPoolSize(pool_size)); } let mut extras = connection_config.clone(); @@ -556,25 +546,25 @@ pub fn database_config<'a>( Ok(DatabaseConfig { url, pool_size: pool_size as u32, extras: extras }) } -impl<'a> Display for DatabaseConfigError { +impl<'a> Display for ConfigError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - DatabaseConfigError::MissingTable => { + ConfigError::MissingTable => { write!(f, "A table named `databases` was not found for this configuration") }, - DatabaseConfigError::MissingKey => { + ConfigError::MissingKey => { write!(f, "An entry in the `databases` table was not found for this key") }, - DatabaseConfigError::MalformedConfiguration => { + ConfigError::MalformedConfiguration => { write!(f, "The configuration for this database is malformed") } - DatabaseConfigError::MissingUrl => { + ConfigError::MissingUrl => { write!(f, "The connection URL is missing for this database") }, - DatabaseConfigError::MalformedUrl => { + ConfigError::MalformedUrl => { write!(f, "The specified connection URL is malformed") }, - DatabaseConfigError::InvalidPoolSize(invalid_size) => { + ConfigError::InvalidPoolSize(invalid_size) => { write!(f, "'{}' is not a valid value for `pool_size`", invalid_size) }, } @@ -782,7 +772,7 @@ impl Poolable for redis::Connection { mod tests { use std::collections::BTreeMap; use rocket::{Config, config::{Environment, Value}}; - use super::{DatabaseConfigError::*, database_config}; + use super::{ConfigError::*, database_config}; #[test] fn no_database_entry_in_config_returns_error() { diff --git a/contrib/lib/src/json.rs b/contrib/lib/src/json.rs @@ -1,3 +1,6 @@ +extern crate serde; +extern crate serde_json; + use std::ops::{Deref, DerefMut}; use std::io::{self, Read}; @@ -7,25 +10,32 @@ use rocket::data::{Outcome, Transform, Transform::*, Transformed, Data, FromData use rocket::response::{self, Responder, content}; use rocket::http::Status; -use serde::{Serialize, Serializer}; -use serde::de::{Deserialize, Deserializer}; -use serde_json; +use self::serde::{Serialize, Serializer}; +use self::serde::de::{Deserialize, Deserializer}; + +#[doc(hidden)] +pub use self::serde_json::{json_internal, json_internal_vec}; -/// The JSON type: implements `FromData` and `Responder`, allowing you to easily -/// consume and respond with JSON. +/// The JSON type: implements [`FromData`] and [`Responder`], allowing you to +/// easily consume and respond with JSON. /// /// ## Receiving JSON /// /// If you're receiving JSON data, simply add a `data` parameter to your route /// arguments and ensure the type of the parameter is a `Json<T>`, where `T` is -/// some type you'd like to parse from JSON. `T` must implement `Deserialize` or -/// `DeserializeOwned` from [`serde`](https://github.com/serde-rs/json). The -/// data is parsed from the HTTP request body. +/// some type you'd like to parse from JSON. `T` must implement [`Deserialize`] +/// or from [`serde`]. The data is parsed from the HTTP request body. +/// +/// ```rust +/// # #![feature(proc_macro_hygiene, decl_macro)] +/// # #[macro_use] extern crate rocket; +/// # extern crate rocket_contrib; +/// # type User = usize; +/// use rocket_contrib::json::Json; /// -/// ```rust,ignore -/// #[post("/users/", format = "json", data = "<user>")] +/// #[post("/users", format = "json", data = "<user>")] /// fn new_user(user: Json<User>) { -/// ... +/// /* ... */ /// } /// ``` /// @@ -37,14 +47,20 @@ use serde_json; /// ## Sending JSON /// /// If you're responding with JSON data, return a `Json<T>` type, where `T` -/// implements `Serialize` from [Serde](https://github.com/serde-rs/json). The -/// content type of the response is set to `application/json` automatically. +/// implements [`Serialize`] from [`serde`]. The content type of the response is +/// set to `application/json` automatically. +/// +/// ```rust +/// # #![feature(proc_macro_hygiene, decl_macro)] +/// # #[macro_use] extern crate rocket; +/// # extern crate rocket_contrib; +/// # type User = usize; +/// use rocket_contrib::json::Json; /// -/// ```rust,ignore /// #[get("/users/<id>")] /// fn user(id: usize) -> Json<User> { /// let user_from_id = User::from(id); -/// ... +/// /* ... */ /// Json(user_from_id) /// } /// ``` @@ -70,7 +86,7 @@ impl<T> Json<T> { /// /// # Example /// ```rust - /// # use rocket_contrib::Json; + /// # use rocket_contrib::json::Json; /// let string = "Hello".to_string(); /// let my_json = Json(string); /// assert_eq!(my_json.into_inner(), "Hello".to_string()); @@ -183,7 +199,7 @@ impl<T> DerefMut for Json<T> { /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket_contrib; -/// use rocket_contrib::JsonValue; +/// use rocket_contrib::json::JsonValue; /// /// #[get("/json")] /// fn get_json() -> JsonValue { @@ -265,14 +281,14 @@ impl<'a> Responder<'a> for JsonValue { /// #[macro_use] extern crate rocket_contrib; /// ``` /// -/// The return type of a `json!` invocation is [`JsonValue`]. A value created -/// with this macro can be returned from a handler as follows: +/// The return type of a `json!` invocation is [`JsonValue`](json::JsonValue). A +/// value created with this macro can be returned from a handler as follows: /// /// ```rust /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket_contrib; -/// use rocket_contrib::JsonValue; +/// use rocket_contrib::json::JsonValue; /// /// #[get("/json")] /// fn get_json() -> JsonValue { @@ -283,9 +299,9 @@ impl<'a> Responder<'a> for JsonValue { /// } /// ``` /// -/// The `Responder` implementation for `JsonValue` serializes the value into a -/// JSON string and sets it as the body of the response with a `Content-Type` of -/// `application/json`. +/// The [`Responder`](rocket::response::Responder) implementation for +/// `JsonValue` serializes the value into a JSON string and sets it as the body +/// of the response with a `Content-Type` of `application/json`. /// /// # Examples /// @@ -358,6 +374,6 @@ impl<'a> Responder<'a> for JsonValue { #[macro_export] macro_rules! json { ($($json:tt)+) => { - $crate::JsonValue(json_internal!($($json)+)) + $crate::json::JsonValue($crate::json::json_internal!($($json)+)) }; } diff --git a/contrib/lib/src/lib.rs b/contrib/lib/src/lib.rs @@ -16,13 +16,13 @@ //! common modules exposed by default. The present feature list is below, with //! an asterisk next to the features that are enabled by default: //! -//! * [json*](Json) -//! * [static_files*](static_files) -//! * [msgpack](MsgPack) -//! * [handlebars_templates](Template) -//! * [tera_templates](Template) -//! * [uuid](Uuid) -//! * [${database}_pool](databases) +//! * [json*](type@json) - JSON (de)serialization +//! * [serve*](serve) - Static File Serving +//! * [msgpack](msgpack) - MessagePack (de)serialization +//! * [handlebars_templates](templates) - Handlebars Templating +//! * [tera_templates](templates) - Tera Templating +//! * [uuid](uuid) - UUID (de)serialization +//! * [${database}_pool](databases) - Database Configuration and Pooling //! //! The recommend way to include features from this crate via Cargo in your //! project is by adding a `[dependencies.rocket_contrib]` section to your @@ -42,59 +42,14 @@ #[allow(unused_imports)] #[macro_use] extern crate log; #[allow(unused_imports)] #[macro_use] extern crate rocket; -#[cfg(feature = "serde")] -extern crate serde; +#[cfg(feature="json")] #[macro_use] pub mod json; +#[cfg(feature="serve")] pub mod serve; +#[cfg(feature="msgpack")] pub mod msgpack; +#[cfg(feature="templates")] pub mod templates; +#[cfg(feature="uuid")] pub mod uuid; +#[cfg(feature="databases")] pub mod databases; -#[cfg(feature = "json")] -extern crate serde_json; - -#[cfg(feature = "json")] -pub use serde_json::{json_internal, json_internal_vec}; - -#[cfg(feature = "handlebars_templates")] -pub extern crate handlebars; - -#[cfg(feature = "tera_templates")] -pub extern crate tera; - -#[cfg(feature = "json")] -#[cfg_attr(feature = "json", macro_use)] -#[doc(hidden)] -pub mod json; - -#[cfg(feature = "json")] -pub use json::{Json, JsonError, JsonValue}; - -#[cfg(feature = "msgpack")] -#[doc(hidden)] -pub mod msgpack; - -#[cfg(feature = "msgpack")] -pub use msgpack::{MsgPack, MsgPackError}; - -#[cfg(feature = "templates")] -mod templates; - -#[cfg(feature = "templates")] -pub use templates::{Engines, Template, TemplateMetadata}; - -#[cfg(feature = "uuid")] -mod uuid; - -#[cfg(feature = "uuid")] -pub use uuid::{Uuid, UuidParseError}; - -#[cfg(feature = "static_files")] -pub mod static_files; - -#[cfg(feature = "database_pool")] -pub mod databases; - -#[cfg(feature = "database_pool_codegen")] #[allow(unused_imports)] #[macro_use] +#[cfg(feature="databases")] extern crate rocket_contrib_codegen; - -#[cfg(feature = "database_pool_codegen")] -#[doc(hidden)] -pub use rocket_contrib_codegen::*; diff --git a/contrib/lib/src/msgpack.rs b/contrib/lib/src/msgpack.rs @@ -1,3 +1,4 @@ +extern crate serde; extern crate rmp_serde; use std::ops::{Deref, DerefMut}; @@ -9,31 +10,28 @@ use rocket::data::{Outcome, Transform, Transform::*, Transformed, Data, FromData use rocket::response::{self, Responder, Response}; use rocket::http::Status; -use serde::Serialize; -use serde::de::Deserialize; +use self::serde::Serialize; +use self::serde::de::Deserialize; -pub use self::rmp_serde::decode::Error as MsgPackError; +pub use self::rmp_serde::decode::Error; -/// The `MsgPack` type: implements `FromData` and `Responder`, allowing you to -/// easily consume and respond with MessagePack data. +/// The `MsgPack` type: implements [`FromData`] and [`Responder`], allowing you +/// to easily consume and respond with MessagePack data. /// /// ## Receiving MessagePack /// /// If you're receiving MessagePack data, simply add a `data` parameter to your /// route arguments and ensure the type of the parameter is a `MsgPack<T>`, /// where `T` is some type you'd like to parse from MessagePack. `T` must -/// implement `Deserialize` or `DeserializeOwned` from -/// [`serde`](https://github.com/serde-rs/serde). The data is parsed from the -/// HTTP request body. +/// implement [`Deserialize`] from [`serde`]. The data is parsed from the HTTP +/// request body. /// /// ```rust /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # extern crate rocket_contrib; /// # type User = usize; -/// # fn main() { } -/// # -/// use rocket_contrib::MsgPack; +/// use rocket_contrib::msgpack::MsgPack; /// /// #[post("/users", format = "msgpack", data = "<user>")] /// fn new_user(user: MsgPack<User>) { @@ -49,18 +47,15 @@ pub use self::rmp_serde::decode::Error as MsgPackError; /// ## Sending MessagePack /// /// If you're responding with MessagePack data, return a `MsgPack<T>` type, -/// where `T` implements `Serialize` from -/// [serde](https://github.com/serde-rs/serde). The content type of the response -/// is set to `application/msgpack` automatically. +/// where `T` implements [`Serialize`] from [`serde`]. The content type of the +/// response is set to `application/msgpack` automatically. /// /// ```rust /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # extern crate rocket_contrib; /// # type User = usize; -/// # fn main() { } -/// # -/// use rocket_contrib::MsgPack; +/// use rocket_contrib::msgpack::MsgPack; /// /// #[get("/users/<id>")] /// fn user(id: usize) -> MsgPack<User> { @@ -92,7 +87,7 @@ impl<T> MsgPack<T> { /// # Example /// /// ```rust - /// # use rocket_contrib::MsgPack; + /// # use rocket_contrib::msgpack::MsgPack; /// let string = "Hello".to_string(); /// let my_msgpack = MsgPack(string); /// assert_eq!(my_msgpack.into_inner(), "Hello".to_string()); @@ -107,7 +102,7 @@ impl<T> MsgPack<T> { const LIMIT: u64 = 1 << 20; impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> { - type Error = MsgPackError; + type Error = Error; type Owned = Vec<u8>; type Borrowed = [u8]; @@ -116,12 +111,12 @@ impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> { let size_limit = r.limits().get("msgpack").unwrap_or(LIMIT); match d.open().take(size_limit).read_to_end(&mut buf) { Ok(_) => Borrowed(Success(buf)), - Err(e) => Borrowed(Failure((Status::BadRequest, MsgPackError::InvalidDataRead(e)))) + Err(e) => Borrowed(Failure((Status::BadRequest, Error::InvalidDataRead(e)))) } } fn from_data(_: &Request, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { - use self::MsgPackError::*; + use self::Error::*; let buf = o.borrowed()?; match rmp_serde::from_slice(&buf) { diff --git a/contrib/lib/src/serve.rs b/contrib/lib/src/serve.rs @@ -0,0 +1,242 @@ +//! Custom handler and options for static file serving. + +use std::path::{PathBuf, Path}; + +use rocket::{Request, Data, Route}; +use rocket::http::{Method, Status, uri::Segments}; +use rocket::handler::{Handler, Outcome}; +use rocket::response::NamedFile; +use rocket::outcome::IntoOutcome; + +/// A bitset representing configurable options for the [`StaticFiles`] handler. +/// +/// The valid options are: +/// +/// * [`Options::None`] - Return only present, visible files. +/// * [`Options::DotFiles`] - In addition to visible files, return dotfiles. +/// * [`Options::Index`] - Render `index.html` pages for directory requests. +/// +/// Two `Options` structures can be `or`d together to slect two or more options. +/// For instance, to request that both dot files and index pages be returned, +/// use `Options::DotFiles | Options::Index`. +#[derive(Debug, Clone, Copy)] +pub struct Options(u8); + +#[allow(non_upper_case_globals)] +impl Options { + /// `Options` representing the empty set. No dotfiles or index pages are + /// rendered. This is different than the _default_, which enables `Index`. + pub const None: Options = Options(0b0000); + + /// `Options` enabling responding to requests for a directory with the + /// `index.html` file in that directory, if it exists. When this is enabled, + /// the [`StaticFiles`] handler will respond to requests for a directory + /// `/foo` with the file `${root}/foo/index.html` if it exists. This is + /// enabled by default. + pub const Index: Options = Options(0b0001); + + /// `Options` enabling returning dot files. When this is enabled, the + /// [`StaticFiles`] handler will respond to requests for files or + /// directories beginning with `.`. This is _not_ enabled by default. + pub const DotFiles: Options = Options(0b0010); + + /// Returns `true` if `self` is a superset of `other`. In other words, + /// returns `true` if all of the options in `other` are also in `self`. + /// + /// # Example + /// + /// ```rust + /// use rocket_contrib::serve::Options; + /// + /// let index_request = Options::Index | Options::DotFiles; + /// assert!(index_request.contains(Options::Index)); + /// assert!(index_request.contains(Options::DotFiles)); + /// + /// let index_only = Options::Index; + /// assert!(index_only.contains(Options::Index)); + /// assert!(!index_only.contains(Options::DotFiles)); + /// + /// let dot_only = Options::DotFiles; + /// assert!(dot_only.contains(Options::DotFiles)); + /// assert!(!dot_only.contains(Options::Index)); + /// ``` + #[inline] + pub fn contains(self, other: Options) -> bool { + (other.0 & self.0) == other.0 + } +} + +impl ::std::ops::BitOr for Options { + type Output = Self; + + #[inline(always)] + fn bitor(self, rhs: Self) -> Self { + Options(self.0 | rhs.0) + } +} + +/// Custom handler for serving static files. +/// +/// This handler makes it simple to serve static files from a directory on the +/// local file system. To use it, construct a `StaticFiles` using either +/// [`StaticFiles::from()`] or [`StaticFiles::new()`] then simply `mount` the +/// handler at a desired path. +/// +/// # Options +/// +/// The handler's functionality can be customized by passing an [`Options`] to +/// [`StaticFiles::new()`]. +/// +/// # Example +/// +/// To serve files from this directory at the `/public` path, allowing +/// `index.html` files to be used to respond to requests for a directory (the +/// default), you might write the following: +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::serve::StaticFiles; +/// +/// fn main() { +/// # if false { +/// rocket::ignite() +/// .mount("/public", StaticFiles::from("/static")) +/// .launch(); +/// # } +/// } +/// ``` +/// +/// With this set-up, requests for files at `/public/<path..>` will be handled +/// by returning the contents of `/static/<path..>`. Requests for _directories_ +/// at `/public/<directory>` will be handled by returning the contents of +/// `/static/<directory>/index.html`. +/// +/// If your static files are stored relative to your crate and your project is +/// managed by Cargo, you should either use a relative path and ensure that your +/// server is started in the crate's root directory or use the +/// `CARGO_MANIFEST_DIR` to create an absolute path relative to your crate root. +/// For example, to serve files in the `static` subdirectory of your crate at +/// `/`, you might write: +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::serve::StaticFiles; +/// +/// fn main() { +/// # if false { +/// rocket::ignite() +/// .mount("/", StaticFiles::from(concat!(env!("CARGO_MANIFEST_DIR"), "/static"))) +/// .launch(); +/// # } +/// } +/// ``` +#[derive(Clone)] +pub struct StaticFiles { + root: PathBuf, + options: Options, +} + +impl StaticFiles { + /// Constructs a new `StaticFiles` that serves files from the file system + /// `path`. By default, [`Options::Index`] is enabled. To serve static files + /// with other options, use [`StaticFiles::new()`]. + /// + /// # Example + /// + /// Serve the static files in the `/www/public` local directory on path + /// `/static`. + /// + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// use rocket_contrib::serve::StaticFiles; + /// + /// fn main() { + /// # if false { + /// rocket::ignite() + /// .mount("/static", StaticFiles::from("/www/public")) + /// .launch(); + /// # } + /// } + /// ``` + pub fn from<P: AsRef<Path>>(path: P) -> Self { + StaticFiles::new(path, Options::Index) + } + + /// Constructs a new `StaticFiles` that serves files from the file system + /// `path` with `options` enabled. + /// + /// # Example + /// + /// Serve the static files in the `/www/public` local directory on path + /// `/static` without serving index files or dot files. Additionally, serve + /// the same files on `/pub` while also seriving index files and dot files. + /// + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// use rocket_contrib::serve::{StaticFiles, Options}; + /// + /// fn main() { + /// # if false { + /// let options = Options::Index | Options::DotFiles; + /// rocket::ignite() + /// .mount("/static", StaticFiles::from("/www/public")) + /// .mount("/pub", StaticFiles::new("/www/public", options)) + /// .launch(); + /// # } + /// } + /// ``` + pub fn new<P: AsRef<Path>>(path: P, options: Options) -> Self { + StaticFiles { root: path.as_ref().into(), options } + } +} + +impl Into<Vec<Route>> for StaticFiles { + fn into(self) -> Vec<Route> { + let non_index = Route::ranked(10, Method::Get, "/<path..>", self.clone()); + if self.options.contains(Options::Index) { + let index = Route::ranked(10, Method::Get, "/", self); + vec![index, non_index] + } else { + vec![non_index] + } + } +} + +impl Handler for StaticFiles { + fn handle<'r>(&self, req: &'r Request, _: Data) -> Outcome<'r> { + fn handle_index<'r>(opt: Options, r: &'r Request, path: &Path) -> Outcome<'r> { + if !opt.contains(Options::Index) { + return Outcome::failure(Status::NotFound); + } + + Outcome::from(r, NamedFile::open(path.join("index.html")).ok()) + } + + // If this is not the route with segments, handle it only if the user + // requested a handling of index files. + let current_route = req.route().expect("route while handling"); + let is_segments_route = current_route.uri.path().ends_with(">"); + if !is_segments_route { + return handle_index(self.options, req, &self.root); + } + + // Otherwise, we're handling segments. Get the segments as a `PathBuf`, + // only allowing dotfiles if the user allowed it. + let allow_dotfiles = self.options.contains(Options::DotFiles); + let path = req.get_segments::<Segments>(0) + .and_then(|res| res.ok()) + .and_then(|segments| segments.into_path_buf(allow_dotfiles).ok()) + .map(|path| self.root.join(path)) + .into_outcome(Status::NotFound)?; + + if path.is_dir() { + handle_index(self.options, req, &path) + } else { + Outcome::from(req, NamedFile::open(&path).ok()) + } + } +} diff --git a/contrib/lib/src/static_files.rs b/contrib/lib/src/static_files.rs @@ -1,242 +0,0 @@ -//! Custom handler and options for static file serving. - -use std::path::{PathBuf, Path}; - -use rocket::{Request, Data, Route}; -use rocket::http::{Method, Status, uri::Segments}; -use rocket::handler::{Handler, Outcome}; -use rocket::response::NamedFile; -use rocket::outcome::IntoOutcome; - -/// A bitset representing configurable options for the [`StaticFiles`] handler. -/// -/// The valid options are: -/// -/// * [`Options::None`] - Return only present, visible files. -/// * [`Options::DotFiles`] - In addition to visible files, return dotfiles. -/// * [`Options::Index`] - Render `index.html` pages for directory requests. -/// -/// Two `Options` structures can be `or`d together to slect two or more options. -/// For instance, to request that both dot files and index pages be returned, -/// use `Options::DotFiles | Options::Index`. -#[derive(Debug, Clone, Copy)] -pub struct Options(u8); - -#[allow(non_upper_case_globals)] -impl Options { - /// `Options` representing the empty set. No dotfiles or index pages are - /// rendered. This is different than the _default_, which enables `Index`. - pub const None: Options = Options(0b0000); - - /// `Options` enabling responding to requests for a directory with the - /// `index.html` file in that directory, if it exists. When this is enabled, - /// the [`StaticFiles`] handler will respond to requests for a directory - /// `/foo` with the file `${root}/foo/index.html` if it exists. This is - /// enabled by default. - pub const Index: Options = Options(0b0001); - - /// `Options` enabling returning dot files. When this is enabled, the - /// [`StaticFiles`] handler will respond to requests for files or - /// directories beginning with `.`. This is _not_ enabled by default. - pub const DotFiles: Options = Options(0b0010); - - /// Returns `true` if `self` is a superset of `other`. In other words, - /// returns `true` if all of the options in `other` are also in `self`. - /// - /// # Example - /// - /// ```rust - /// use rocket_contrib::static_files::Options; - /// - /// let index_request = Options::Index | Options::DotFiles; - /// assert!(index_request.contains(Options::Index)); - /// assert!(index_request.contains(Options::DotFiles)); - /// - /// let index_only = Options::Index; - /// assert!(index_only.contains(Options::Index)); - /// assert!(!index_only.contains(Options::DotFiles)); - /// - /// let dot_only = Options::DotFiles; - /// assert!(dot_only.contains(Options::DotFiles)); - /// assert!(!dot_only.contains(Options::Index)); - /// ``` - #[inline] - pub fn contains(self, other: Options) -> bool { - (other.0 & self.0) == other.0 - } -} - -impl ::std::ops::BitOr for Options { - type Output = Self; - - #[inline(always)] - fn bitor(self, rhs: Self) -> Self { - Options(self.0 | rhs.0) - } -} - -/// Custom handler for serving static files. -/// -/// This handler makes it simple to serve static files from a directory on the -/// local file system. To use it, construct a `StaticFiles` using either -/// [`StaticFiles::from()`] or [`StaticFiles::new()`] then simply `mount` the -/// handler at a desired path. -/// -/// # Options -/// -/// The handler's functionality can be customized by passing an [`Options`] to -/// [`StaticFiles::new()`]. -/// -/// # Example -/// -/// To serve files from this directory at the `/public` path, allowing -/// `index.html` files to be used to respond to requests for a directory (the -/// default), you might write the following: -/// -/// ```rust -/// # extern crate rocket; -/// # extern crate rocket_contrib; -/// use rocket_contrib::static_files::StaticFiles; -/// -/// fn main() { -/// # if false { -/// rocket::ignite() -/// .mount("/public", StaticFiles::from("/static")) -/// .launch(); -/// # } -/// } -/// ``` -/// -/// With this set-up, requests for files at `/public/<path..>` will be handled -/// by returning the contents of `/static/<path..>`. Requests for _directories_ -/// at `/public/<directory>` will be handled by returning the contents of -/// `/static/<directory>/index.html`. -/// -/// If your static files are stored relative to your crate and your project is -/// managed by Cargo, you should either use a relative path and ensure that your -/// server is started in the crate's root directory or use the -/// `CARGO_MANIFEST_DIR` to create an absolute path relative to your crate root. -/// For example, to serve files in the `static` subdirectory of your crate at -/// `/`, you might write: -/// -/// ```rust -/// # extern crate rocket; -/// # extern crate rocket_contrib; -/// use rocket_contrib::static_files::StaticFiles; -/// -/// fn main() { -/// # if false { -/// rocket::ignite() -/// .mount("/", StaticFiles::from(concat!(env!("CARGO_MANIFEST_DIR"), "/static"))) -/// .launch(); -/// # } -/// } -/// ``` -#[derive(Clone)] -pub struct StaticFiles { - root: PathBuf, - options: Options, -} - -impl StaticFiles { - /// Constructs a new `StaticFiles` that serves files from the file system - /// `path`. By default, [`Options::Index`] is enabled. To serve static files - /// with other options, use [`StaticFiles::new()`]. - /// - /// # Example - /// - /// Serve the static files in the `/www/public` local directory on path - /// `/static`. - /// - /// ```rust - /// # extern crate rocket; - /// # extern crate rocket_contrib; - /// use rocket_contrib::static_files::StaticFiles; - /// - /// fn main() { - /// # if false { - /// rocket::ignite() - /// .mount("/static", StaticFiles::from("/www/public")) - /// .launch(); - /// # } - /// } - /// ``` - pub fn from<P: AsRef<Path>>(path: P) -> Self { - StaticFiles::new(path, Options::Index) - } - - /// Constructs a new `StaticFiles` that serves files from the file system - /// `path` with `options` enabled. - /// - /// # Example - /// - /// Serve the static files in the `/www/public` local directory on path - /// `/static` without serving index files or dot files. Additionally, serve - /// the same files on `/pub` while also seriving index files and dot files. - /// - /// ```rust - /// # extern crate rocket; - /// # extern crate rocket_contrib; - /// use rocket_contrib::static_files::{StaticFiles, Options}; - /// - /// fn main() { - /// # if false { - /// let options = Options::Index | Options::DotFiles; - /// rocket::ignite() - /// .mount("/static", StaticFiles::from("/www/public")) - /// .mount("/pub", StaticFiles::new("/www/public", options)) - /// .launch(); - /// # } - /// } - /// ``` - pub fn new<P: AsRef<Path>>(path: P, options: Options) -> Self { - StaticFiles { root: path.as_ref().into(), options } - } -} - -impl Into<Vec<Route>> for StaticFiles { - fn into(self) -> Vec<Route> { - let non_index = Route::ranked(10, Method::Get, "/<path..>", self.clone()); - if self.options.contains(Options::Index) { - let index = Route::ranked(10, Method::Get, "/", self); - vec![index, non_index] - } else { - vec![non_index] - } - } -} - -impl Handler for StaticFiles { - fn handle<'r>(&self, req: &'r Request, _: Data) -> Outcome<'r> { - fn handle_index<'r>(opt: Options, r: &'r Request, path: &Path) -> Outcome<'r> { - if !opt.contains(Options::Index) { - return Outcome::failure(Status::NotFound); - } - - Outcome::from(r, NamedFile::open(path.join("index.html")).ok()) - } - - // If this is not the route with segments, handle it only if the user - // requested a handling of index files. - let current_route = req.route().expect("route while handling"); - let is_segments_route = current_route.uri.path().ends_with(">"); - if !is_segments_route { - return handle_index(self.options, req, &self.root); - } - - // Otherwise, we're handling segments. Get the segments as a `PathBuf`, - // only allowing dotfiles if the user allowed it. - let allow_dotfiles = self.options.contains(Options::DotFiles); - let path = req.get_segments::<Segments>(0) - .and_then(|res| res.ok()) - .and_then(|segments| segments.into_path_buf(allow_dotfiles).ok()) - .map(|path| self.root.join(path)) - .into_outcome(Status::NotFound)?; - - if path.is_dir() { - handle_index(self.options, req, &path) - } else { - Outcome::from(req, NamedFile::open(&path).ok()) - } - } -} diff --git a/contrib/lib/src/templates/context.rs b/contrib/lib/src/templates/context.rs @@ -1,18 +1,17 @@ use std::path::{Path, PathBuf}; use std::collections::HashMap; -use super::{Engines, TemplateInfo}; -use super::glob; +use templates::{glob, Engines, TemplateInfo}; use rocket::http::ContentType; -pub struct Context { +crate struct Context { /// The root of the template directory. - pub root: PathBuf, + crate root: PathBuf, /// Mapping from template name to its information. - pub templates: HashMap<String, TemplateInfo>, + crate templates: HashMap<String, TemplateInfo>, /// Loaded template engines - pub engines: Engines, + crate engines: Engines, } impl Context { diff --git a/contrib/lib/src/templates/engine.rs b/contrib/lib/src/templates/engine.rs @@ -1,19 +1,17 @@ use std::collections::HashMap; -use super::serde::Serialize; -use super::TemplateInfo; +use templates::{TemplateInfo, serde::Serialize}; -#[cfg(feature = "tera_templates")] use super::tera_templates::Tera; -#[cfg(feature = "handlebars_templates")] use super::handlebars_templates::Handlebars; +#[cfg(feature = "tera_templates")] use templates::tera::Tera; +#[cfg(feature = "handlebars_templates")] use templates::handlebars::Handlebars; -pub trait Engine: Send + Sync + 'static { +crate trait Engine: Send + Sync + 'static { const EXT: &'static str; fn init(templates: &[(&str, &TemplateInfo)]) -> Option<Self> where Self: Sized; fn render<C: Serialize>(&self, name: &str, context: C) -> Option<String>; } -#[doc(cfg(feature = "tera_templates"))] /// A structure exposing access to templating engines. /// /// Calling methods on the exposed template engine types may require importing @@ -21,13 +19,14 @@ pub trait Engine: Send + Sync + 'static { /// imported from the reexported crate at the root of `rocket_contrib` to avoid /// version mismatches. For instance, when registering a Tera filter, the /// [`tera::Value`] and [`tera::Result`] types are required. Import them from -/// `rocket_contrib::tera`. The example below illustrates this: +/// `rocket_contrib::templates::tera`. The example below illustrates this: /// /// ```rust +/// # #[cfg(feature = "tera_templates")] { /// use std::collections::HashMap; /// -/// use rocket_contrib::{Template, Engines}; -/// use rocket_contrib::tera::{self, Value}; +/// use rocket_contrib::templates::{Template, Engines}; +/// use rocket_contrib::templates::tera::{self, Value}; /// /// fn my_filter(value: Value, _: HashMap<String, Value>) -> tera::Result<Value> { /// # /* @@ -38,25 +37,22 @@ pub trait Engine: Send + Sync + 'static { /// Template::custom(|engines: &mut Engines| { /// engines.tera.register_filter("my_filter", my_filter); /// }); +/// # } /// ``` /// -/// [`tera::Value`]: ::tera::Value -/// [`tera::Result`]: ::tera::Result +/// [`tera::Value`]: ::templates::tera::Value +/// [`tera::Result`]: ::templates::tera::Result pub struct Engines { - #[cfg(feature = "tera_templates")] - /// A [`Tera`] structure. This field is only available when the + /// A `Tera` templating engine. This field is only available when the /// `tera_templates` feature is enabled. When calling methods on the `Tera` - /// instance, ensure you use types imported from `rocket_contrib::tera` to - /// avoid version mismatches. - /// - /// [`Tera`]: tera::Tera + /// instance, ensure you use types imported from + /// `rocket_contrib::templates::tera` to avoid version mismatches. + #[cfg(feature = "tera_templates")] pub tera: Tera, - /// A [`Handlebars`] structure. This field is only available when the + /// The Handlebars templating engine. This field is only available when the /// `handlebars_templates` feature is enabled. When calling methods on the - /// `Tera` instance, ensure you use types - /// imported from `rocket_contrib::handlebars` to avoid version mismatches. - /// - /// [`Handlebars`]: handlebars::Handlebars + /// `Tera` instance, ensure you use types imported from + /// `rocket_contrib::templates::handlebars` to avoid version mismatches. #[cfg(feature = "handlebars_templates")] pub handlebars: Handlebars, } diff --git a/contrib/lib/src/templates/fairing.rs b/contrib/lib/src/templates/fairing.rs @@ -1,28 +1,26 @@ -use super::DEFAULT_TEMPLATE_DIR; -use super::context::Context; -use super::engine::Engines; +use templates::{DEFAULT_TEMPLATE_DIR, Context, Engines}; use rocket::Rocket; use rocket::config::ConfigError; use rocket::fairing::{Fairing, Info, Kind}; -pub use self::context::ContextManager; +crate use self::context::ContextManager; #[cfg(not(debug_assertions))] mod context { use std::ops::Deref; - use super::Context; + use templates::Context; /// Wraps a Context. With `cfg(debug_assertions)` active, this structure /// additionally provides a method to reload the context at runtime. - pub struct ContextManager(Context); + crate struct ContextManager(Context); impl ContextManager { - pub fn new(ctxt: Context) -> ContextManager { + crate fn new(ctxt: Context) -> ContextManager { ContextManager(ctxt) } - pub fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { + crate fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { &self.0 } } @@ -36,13 +34,13 @@ mod context { use std::sync::{RwLock, Mutex}; use std::sync::mpsc::{channel, Receiver}; - use super::{Context, Engines}; + use templates::{Context, Engines}; use self::notify::{raw_watcher, RawEvent, RecommendedWatcher, RecursiveMode, Watcher}; /// Wraps a Context. With `cfg(debug_assertions)` active, this structure /// additionally provides a method to reload the context at runtime. - pub struct ContextManager { + crate struct ContextManager { /// The current template context, inside an RwLock so it can be updated. context: RwLock<Context>, /// A filesystem watcher and the receive queue for its events. @@ -50,7 +48,7 @@ mod context { } impl ContextManager { - pub fn new(ctxt: Context) -> ContextManager { + crate fn new(ctxt: Context) -> ContextManager { let (tx, rx) = channel(); let watcher = if let Ok(mut watcher) = raw_watcher(tx) { @@ -73,7 +71,7 @@ mod context { } } - pub fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { + crate fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { self.context.read().unwrap() } @@ -85,7 +83,7 @@ mod context { /// have been changes since the last reload, all templates are /// reinitialized from disk and the user's customization callback is run /// again. - pub fn reload_if_needed<F: Fn(&mut Engines)>(&self, custom_callback: F) { + crate fn reload_if_needed<F: Fn(&mut Engines)>(&self, custom_callback: F) { self.watcher.as_ref().map(|w| { let rx_lock = w.lock().expect("receive queue lock"); let mut changed = false; @@ -117,7 +115,7 @@ pub struct TemplateFairing { /// The user-provided customization callback, allowing the use of /// functionality specific to individual template engines. In debug mode, /// this callback might be run multiple times as templates are reloaded. - pub(crate) custom_callback: Box<Fn(&mut Engines) + Send + Sync + 'static>, + crate custom_callback: Box<Fn(&mut Engines) + Send + Sync + 'static>, } impl Fairing for TemplateFairing { diff --git a/contrib/lib/src/templates/handlebars_templates.rs b/contrib/lib/src/templates/handlebars_templates.rs @@ -1,9 +1,7 @@ -extern crate handlebars; +use templates::serde::Serialize; +use templates::{Engine, TemplateInfo}; -use super::serde::Serialize; -use super::{Engine, TemplateInfo}; - -pub use self::handlebars::Handlebars; +pub use templates::handlebars::Handlebars; impl Engine for Handlebars { const EXT: &'static str = "hbs"; diff --git a/contrib/lib/src/templates/metadata.rs b/contrib/lib/src/templates/metadata.rs @@ -2,43 +2,23 @@ use rocket::{Request, State, Outcome}; use rocket::http::Status; use rocket::request::{self, FromRequest}; -use super::ContextManager; +use templates::ContextManager; -/// Implements [`FromRequest`] for dynamiclly querying template metadata. +/// Request guard for dynamiclly querying template metadata. /// /// # Usage /// -/// First, ensure that the template [fairing](rocket::fairing), -/// [`Template::fairing()`](::Template::fairing()) is attached to your Rocket -/// application: -/// -/// ```rust -/// # extern crate rocket; -/// # extern crate rocket_contrib; -/// # -/// use rocket_contrib::Template; -/// -/// fn main() { -/// rocket::ignite() -/// .attach(Template::fairing()) -/// // ... -/// # ; -/// } -/// ``` -/// -/// The `TemplateMetadata` type implements Rocket's `FromRequest` trait, so it -/// can be used as a request guard in any request handler. +/// The `Metadata` type implements Rocket's [`FromRequest`] trait, so it can be +/// used as a request guard in any request handler. /// /// ```rust /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket_contrib; -/// # fn main() { } -/// # -/// use rocket_contrib::{Template, TemplateMetadata}; +/// use rocket_contrib::templates::{Template, Metadata}; /// /// #[get("/")] -/// fn homepage(metadata: TemplateMetadata) -> Template { +/// fn homepage(metadata: Metadata) -> Template { /// # use std::collections::HashMap; /// # let context: HashMap<String, String> = HashMap::new(); /// // Conditionally render a template if it's available. @@ -48,19 +28,27 @@ use super::ContextManager; /// Template::render("fallback", &context) /// } /// } +/// +/// +/// fn main() { +/// rocket::ignite() +/// .attach(Template::fairing()) +/// // ... +/// # ; +/// } /// ``` -pub struct TemplateMetadata<'a>(&'a ContextManager); +pub struct Metadata<'a>(&'a ContextManager); -impl<'a> TemplateMetadata<'a> { +impl<'a> Metadata<'a> { /// Returns `true` if the template with name `name` was loaded at start-up /// time. Otherwise, returns `false`. /// /// # Example /// /// ```rust - /// use rocket_contrib::TemplateMetadata; + /// use rocket_contrib::templates::Metadata; /// - /// fn handler(metadata: TemplateMetadata) { + /// fn handler(metadata: Metadata) { /// // Returns `true` if the template with name `"name"` was loaded. /// let loaded = metadata.contains_template("name"); /// } @@ -73,13 +61,13 @@ impl<'a> TemplateMetadata<'a> { /// Retrieves the template metadata. If a template fairing hasn't been attached, /// an error is printed and an empty `Err` with status `InternalServerError` /// (`500`) is returned. -impl<'a, 'r> FromRequest<'a, 'r> for TemplateMetadata<'a> { +impl<'a, 'r> FromRequest<'a, 'r> for Metadata<'a> { type Error = (); fn from_request(request: &'a Request) -> request::Outcome<Self, ()> { request.guard::<State<ContextManager>>() .succeeded() - .and_then(|cm| Some(Outcome::Success(TemplateMetadata(cm.inner())))) + .and_then(|cm| Some(Outcome::Success(Metadata(cm.inner())))) .unwrap_or_else(|| { error_!("Uninitialized template context: missing fairing."); info_!("To use templates, you must attach `Template::fairing()`."); diff --git a/contrib/lib/src/templates/mod.rs b/contrib/lib/src/templates/mod.rs @@ -2,7 +2,10 @@ extern crate serde; extern crate serde_json; extern crate glob; +#[cfg(feature = "tera_templates")] pub extern crate tera; #[cfg(feature = "tera_templates")] mod tera_templates; + +#[cfg(feature = "handlebars_templates")] pub extern crate handlebars; #[cfg(feature = "handlebars_templates")] mod handlebars_templates; mod engine; @@ -11,11 +14,12 @@ mod context; mod metadata; pub use self::engine::Engines; -pub use self::metadata::TemplateMetadata; +pub use self::metadata::Metadata; +crate use self::context::Context; +crate use self::fairing::ContextManager; use self::engine::Engine; -use self::fairing::{TemplateFairing, ContextManager}; -use self::context::Context; +use self::fairing::TemplateFairing; use self::serde::Serialize; use self::serde_json::{Value, to_value}; use self::glob::glob; @@ -99,14 +103,12 @@ const DEFAULT_TEMPLATE_DIR: &str = "templates"; /// application: /// /// ```rust -/// extern crate rocket; -/// extern crate rocket_contrib; -/// -/// use rocket_contrib::Template; +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::templates::Template; /// /// fn main() { /// rocket::ignite() -/// // ... /// .attach(Template::fairing()) /// // ... /// # ; @@ -116,10 +118,16 @@ const DEFAULT_TEMPLATE_DIR: &str = "templates"; /// The `Template` type implements Rocket's [`Responder`] trait, so it can be /// returned from a request handler directly: /// -/// ```rust,ignore +/// ```rust +/// # #![feature(proc_macro_hygiene, decl_macro)] +/// # #[macro_use] extern crate rocket; +/// # #[macro_use] extern crate rocket_contrib; +/// # fn context() { } +/// use rocket_contrib::templates::Template; +/// /// #[get("/")] /// fn index() -> Template { -/// let context = ...; +/// let context = context(); /// Template::render("index", &context) /// } /// ``` @@ -136,7 +144,7 @@ pub struct Template { } #[derive(Debug)] -pub struct TemplateInfo { +crate struct TemplateInfo { /// The complete path, including `template_dir`, to this template. path: PathBuf, /// The extension for the engine of this template. @@ -166,7 +174,7 @@ impl Template { /// extern crate rocket; /// extern crate rocket_contrib; /// - /// use rocket_contrib::Template; + /// use rocket_contrib::templates::Template; /// /// fn main() { /// rocket::ignite() @@ -192,7 +200,7 @@ impl Template { /// extern crate rocket; /// extern crate rocket_contrib; /// - /// use rocket_contrib::Template; + /// use rocket_contrib::templates::Template; /// /// fn main() { /// rocket::ignite() @@ -218,7 +226,7 @@ impl Template { /// /// ```rust /// use std::collections::HashMap; - /// use rocket_contrib::Template; + /// use rocket_contrib::templates::Template; /// /// // Create a `context`. Here, just an empty `HashMap`. /// let mut context = HashMap::new(); @@ -235,9 +243,9 @@ impl Template { /// Render the template named `name` with the context `context` into a /// `String`. This method should **not** be used in any running Rocket - /// application. This method should only be used during testing to - /// validate `Template` responses. For other uses, use - /// [`render`](#method.render) instead. + /// application. This method should only be used during testing to validate + /// `Template` responses. For other uses, use [`render()`](#method.render) + /// instead. /// /// The `context` can be of any type that implements `Serialize`. This is /// typically a `HashMap` or a custom `struct`. @@ -253,7 +261,7 @@ impl Template { /// # extern crate rocket_contrib; /// use std::collections::HashMap; /// - /// use rocket_contrib::Template; + /// use rocket_contrib::templates::Template; /// use rocket::local::Client; /// /// fn main() { diff --git a/contrib/lib/src/templates/tera_templates.rs b/contrib/lib/src/templates/tera_templates.rs @@ -1,9 +1,7 @@ -extern crate tera; +use templates::serde::Serialize; +use templates::{Engine, TemplateInfo}; -use super::serde::Serialize; -use super::{Engine, TemplateInfo}; - -pub use self::tera::Tera; +pub use templates::tera::Tera; impl Engine for Tera { const EXT: &'static str = "tera"; diff --git a/contrib/lib/src/uuid.rs b/contrib/lib/src/uuid.rs @@ -1,4 +1,4 @@ -extern crate uuid as uuid_ext; +pub extern crate uuid as uuid_crate; use std::fmt; use std::str::FromStr; @@ -7,7 +7,7 @@ use std::ops::Deref; use rocket::request::{FromParam, FromFormValue}; use rocket::http::RawStr; -pub use self::uuid_ext::parser::ParseError as UuidParseError; +pub use self::uuid_crate::parser::ParseError; /// Implements [`FromParam`] and [`FromFormValue`] for accepting UUID values /// from the [`uuid`] crate. @@ -26,7 +26,12 @@ pub use self::uuid_ext::parser::ParseError as UuidParseError; /// /// You can use the `Uuid` type directly as a target of a dynamic parameter: /// -/// ```rust,ignore +/// ```rust +/// # #![feature(proc_macro_hygiene, decl_macro)] +/// # #[macro_use] extern crate rocket; +/// # #[macro_use] extern crate rocket_contrib; +/// use rocket_contrib::uuid::Uuid; +/// /// #[get("/users/<id>")] /// fn user(id: Uuid) -> String { /// format!("We found: {}", id) @@ -35,18 +40,18 @@ pub use self::uuid_ext::parser::ParseError as UuidParseError; /// /// You can also use the `Uuid` as a form value, including in query strings: /// -/// ```rust,ignore -/// #[derive(FromForm)] -/// struct UserQuery { -/// id: Uuid -/// } +/// ```rust +/// # #![feature(proc_macro_hygiene, decl_macro)] +/// # #[macro_use] extern crate rocket; +/// # #[macro_use] extern crate rocket_contrib; +/// use rocket_contrib::uuid::Uuid; /// -/// #[post("/user?<user_query>")] -/// fn user(user_query: UserQuery) -> String { -/// format!("User ID: {}", user_query.id) +/// #[get("/user?<id>")] +/// fn user(id: Uuid) -> String { +/// format!("User ID: {}", id) /// } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct Uuid(uuid_ext::Uuid); +pub struct Uuid(uuid_crate::Uuid); impl Uuid { /// Consumes the Uuid wrapper, returning the underlying `Uuid` type. @@ -54,17 +59,21 @@ impl Uuid { /// # Example /// ```rust /// # extern crate rocket_contrib; - /// # extern crate uuid; /// # use std::str::FromStr; /// # fn main() { + /// use rocket_contrib::uuid::{uuid_crate, Uuid}; + /// /// let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; - /// let real_uuid = uuid::Uuid::from_str(uuid_str).unwrap(); - /// let my_inner_uuid = rocket_contrib::Uuid::from_str(uuid_str).unwrap().into_inner(); + /// let real_uuid = uuid_crate::Uuid::from_str(uuid_str).unwrap(); + /// let my_inner_uuid = Uuid::from_str(uuid_str) + /// .expect("valid UUID string") + /// .into_inner(); + /// /// assert_eq!(real_uuid, my_inner_uuid); /// # } /// ``` #[inline(always)] - pub fn into_inner(self) -> uuid_ext::Uuid { + pub fn into_inner(self) -> uuid_crate::Uuid { self.0 } } @@ -77,10 +86,10 @@ impl fmt::Display for Uuid { } impl<'a> FromParam<'a> for Uuid { - type Error = UuidParseError; + type Error = ParseError; /// A value is successfully parsed if `param` is a properly formatted Uuid. - /// Otherwise, a `UuidParseError` is returned. + /// Otherwise, a `ParseError` is returned. #[inline(always)] fn from_param(param: &'a RawStr) -> Result<Uuid, Self::Error> { param.parse() @@ -99,7 +108,7 @@ impl<'v> FromFormValue<'v> for Uuid { } impl FromStr for Uuid { - type Err = UuidParseError; + type Err = ParseError; #[inline] fn from_str(s: &str) -> Result<Uuid, Self::Err> { @@ -108,23 +117,23 @@ impl FromStr for Uuid { } impl Deref for Uuid { - type Target = uuid_ext::Uuid; + type Target = uuid_crate::Uuid; fn deref(&self) -> &Self::Target { &self.0 } } -impl PartialEq<uuid_ext::Uuid> for Uuid { +impl PartialEq<uuid_crate::Uuid> for Uuid { #[inline(always)] - fn eq(&self, other: &uuid_ext::Uuid) -> bool { + fn eq(&self, other: &uuid_crate::Uuid) -> bool { self.0.eq(other) } } #[cfg(test)] mod test { - use super::uuid_ext; + use super::uuid_crate; use super::Uuid; use super::FromParam; use super::FromStr; @@ -147,8 +156,8 @@ mod test { fn test_into_inner() { let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap(); - let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); - let inner_uuid: uuid_ext::Uuid = uuid_wrapper.into_inner(); + let real_uuid: uuid_crate::Uuid = uuid_str.parse().unwrap(); + let inner_uuid: uuid_crate::Uuid = uuid_wrapper.into_inner(); assert_eq!(real_uuid, inner_uuid) } @@ -156,7 +165,7 @@ mod test { fn test_partial_eq() { let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap(); - let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); + let real_uuid: uuid_crate::Uuid = uuid_str.parse().unwrap(); assert_eq!(uuid_wrapper, real_uuid) } diff --git a/contrib/lib/tests/databases.rs b/contrib/lib/tests/databases.rs @@ -1,7 +1,7 @@ extern crate rocket; extern crate rocket_contrib; -#[cfg(feature = "databases")] +#[cfg(all(feature = "diesel_sqlite_pool", feature = "diesel_postgres_pool"))] mod databases_tests { use rocket_contrib::databases::{database, diesel}; diff --git a/contrib/lib/tests/static_files.rs b/contrib/lib/tests/static_files.rs @@ -3,13 +3,13 @@ extern crate rocket; extern crate rocket_contrib; -#[cfg(feature = "static_files")] -mod static_files_tests { +#[cfg(feature = "static")] +mod static_tests { use std::{io::Read, fs::File}; use std::path::{Path, PathBuf}; use rocket::{self, Rocket}; - use rocket_contrib::static_files::{StaticFiles, Options}; + use rocket_contrib::serve::{StaticFiles, Options}; use rocket::http::Status; use rocket::local::Client; diff --git a/contrib/lib/tests/templates.rs b/contrib/lib/tests/templates.rs @@ -1,6 +1,9 @@ #![feature(proc_macro_hygiene, decl_macro)] +#[cfg(feature = "templates")] #[macro_use] extern crate rocket; + +#[cfg(feature = "templates")] extern crate rocket_contrib; #[cfg(feature = "templates")] @@ -9,10 +12,10 @@ mod templates_tests { use rocket::{Rocket, http::RawStr}; use rocket::config::{Config, Environment}; - use rocket_contrib::{Template, TemplateMetadata}; + use rocket_contrib::templates::{Template, Metadata}; #[get("/<engine>/<name>")] - fn template_check(md: TemplateMetadata, engine: &RawStr, name: &RawStr) -> Option<()> { + fn template_check(md: Metadata, engine: &RawStr, name: &RawStr) -> Option<()> { match md.contains_template(&format!("{}/{}", engine, name)) { true => Some(()), false => None diff --git a/examples/cookies/src/main.rs b/examples/cookies/src/main.rs @@ -1,7 +1,7 @@ #![feature(proc_macro_hygiene, decl_macro)] -extern crate rocket_contrib; #[macro_use] extern crate rocket; +extern crate rocket_contrib; #[cfg(test)] mod tests; @@ -11,7 +11,7 @@ use std::collections::HashMap; use rocket::request::Form; use rocket::response::Redirect; use rocket::http::{Cookie, Cookies}; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; #[derive(FromForm)] struct Message { diff --git a/examples/cookies/src/tests.rs b/examples/cookies/src/tests.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use super::rocket; use rocket::local::Client; use rocket::http::*; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; #[test] fn test_submit() { diff --git a/examples/handlebars_templates/src/main.rs b/examples/handlebars_templates/src/main.rs @@ -8,7 +8,7 @@ extern crate rocket_contrib; use rocket::Request; use rocket::response::Redirect; -use rocket_contrib::{Template, handlebars}; +use rocket_contrib::templates::{Template, handlebars}; use handlebars::{Helper, Handlebars, Context, RenderContext, Output, HelperResult, JsonRender}; diff --git a/examples/handlebars_templates/src/tests.rs b/examples/handlebars_templates/src/tests.rs @@ -3,7 +3,7 @@ use super::{rocket, TemplateContext}; use rocket::local::{Client, LocalResponse}; use rocket::http::Method::*; use rocket::http::Status; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; macro_rules! dispatch { ($method:expr, $path:expr, $test_fn:expr) => ({ diff --git a/examples/json/src/main.rs b/examples/json/src/main.rs @@ -6,10 +6,11 @@ #[cfg(test)] mod tests; -use rocket::State; -use rocket_contrib::{Json, JsonValue}; -use std::collections::HashMap; use std::sync::Mutex; +use std::collections::HashMap; + +use rocket::State; +use rocket_contrib::json::{Json, JsonValue}; // The type to represent the ID of a message. type ID = usize; diff --git a/examples/msgpack/src/main.rs b/examples/msgpack/src/main.rs @@ -6,7 +6,7 @@ extern crate rocket_contrib; #[cfg(test)] mod tests; -use rocket_contrib::MsgPack; +use rocket_contrib::msgpack::MsgPack; #[derive(Serialize, Deserialize)] struct Message<'r> { diff --git a/examples/session/src/main.rs b/examples/session/src/main.rs @@ -11,7 +11,7 @@ use rocket::outcome::IntoOutcome; use rocket::request::{self, Form, FlashMessage, FromRequest, Request}; use rocket::response::{Redirect, Flash}; use rocket::http::{Cookie, Cookies}; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; #[derive(FromForm)] struct Login { diff --git a/examples/static_files/src/main.rs b/examples/static_files/src/main.rs @@ -3,7 +3,7 @@ extern crate rocket_contrib; #[cfg(test)] mod tests; -use rocket_contrib::static_files::StaticFiles; +use rocket_contrib::serve::StaticFiles; fn rocket() -> rocket::Rocket { rocket::ignite().mount("/", StaticFiles::from("static")) diff --git a/examples/tera_templates/src/main.rs b/examples/tera_templates/src/main.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use rocket::Request; use rocket::response::Redirect; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; #[derive(Serialize)] struct TemplateContext { diff --git a/examples/tera_templates/src/tests.rs b/examples/tera_templates/src/tests.rs @@ -2,7 +2,7 @@ use super::rocket; use rocket::local::{Client, LocalResponse}; use rocket::http::Method::*; use rocket::http::Status; -use rocket_contrib::Template; +use rocket_contrib::templates::Template; macro_rules! dispatch { ($method:expr, $path:expr, $test_fn:expr) => ({ diff --git a/examples/todo/Cargo.toml b/examples/todo/Cargo.toml @@ -20,4 +20,4 @@ rand = "0.5" [dependencies.rocket_contrib] path = "../../contrib/lib" default_features = false -features = ["tera_templates", "diesel_sqlite_pool", "static_files"] +features = ["tera_templates", "diesel_sqlite_pool", "serve"] diff --git a/examples/todo/src/main.rs b/examples/todo/src/main.rs @@ -14,7 +14,7 @@ use rocket::Rocket; use rocket::fairing::AdHoc; use rocket::request::{Form, FlashMessage}; use rocket::response::{Flash, Redirect}; -use rocket_contrib::{Template, databases::database, static_files::StaticFiles}; +use rocket_contrib::{templates::Template, databases::database, serve::StaticFiles}; use diesel::SqliteConnection; use task::{Task, Todo}; diff --git a/examples/uuid/src/main.rs b/examples/uuid/src/main.rs @@ -2,18 +2,18 @@ #[macro_use] extern crate rocket; #[macro_use] extern crate lazy_static; -extern crate uuid; extern crate rocket_contrib; +extern crate uuid; use std::collections::HashMap; -use rocket_contrib::Uuid; +use rocket_contrib::uuid::Uuid; #[cfg(test)] mod tests; lazy_static! { // A small people lookup table for the sake of this example. In a real // application this could be a database lookup. Notice that we use the - // uuid::Uuid type here and not the rocket_contrib::Uuid type. + // uuid::Uuid type here and not the rocket_contrib::uuid::Uuid type. static ref PEOPLE: HashMap<uuid::Uuid, &'static str> = { let mut m = HashMap::new(); let lacy_id = uuid::Uuid::parse_str("7f205202-7ba1-4c39-b2fc-3e630722bf9f").unwrap(); @@ -29,7 +29,7 @@ lazy_static! { #[get("/people/<id>")] fn people(id: Uuid) -> Result<String, String> { // Because Uuid implements the Deref trait, we use Deref coercion to convert - // rocket_contrib::Uuid to uuid::Uuid. + // rocket_contrib::uuid::Uuid to uuid::Uuid. Ok(PEOPLE.get(&id) .map(|person| format!("We found: {}", person)) .ok_or_else(|| format!("Person not found for UUID: {}", id))?) diff --git a/scripts/test.sh b/scripts/test.sh @@ -85,7 +85,7 @@ if [ "$1" = "--contrib" ]; then msgpack tera_templates handlebars_templates - static_files + serve diesel_postgres_pool diesel_sqlite_pool diesel_mysql_pool