Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typemap into shio #21

Merged
merged 1 commit into from Sep 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Expand Up @@ -20,7 +20,7 @@ hyper = "0.11"
tokio-proto = "0.1.1"
regex = "0.2"
log = "0.3"
typemap = "0.3"
unsafe-any = "0.4.2"

[features]
default = []
Expand Down
4 changes: 2 additions & 2 deletions lib/src/context.rs
@@ -1,10 +1,10 @@
use std::ops::Deref;

use tokio_core::reactor::Handle;
use typemap::TypeMap;
pub use typemap::Key;

use request::{Body, Request};
use utils::typemap::TypeMap;
pub use utils::typemap::Key;

/// `Context` represents the context of the current HTTP request.
///
Expand Down
4 changes: 3 additions & 1 deletion lib/src/lib.rs
@@ -1,5 +1,6 @@
#![cfg_attr(feature = "cargo-clippy", warn(clippy, clippy_pedantic))]
#![cfg_attr(feature = "cargo-clippy", allow(missing_docs_in_private_items))]
#![cfg_attr(feature = "nightly", feature(specialization))]

extern crate futures;
extern crate hyper;
Expand All @@ -10,7 +11,7 @@ extern crate num_cpus;
extern crate regex;
extern crate tokio_core;
extern crate tokio_io;
extern crate typemap;
extern crate unsafe_any;

pub mod context;
mod handler;
Expand All @@ -21,6 +22,7 @@ pub mod response;
pub mod request;
pub mod errors;
pub mod router;
pub mod utils;

pub use hyper::{header, Method, StatusCode};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/router/parameters.rs
Expand Up @@ -2,7 +2,7 @@ use std::ops::Index;
use std::sync::Arc;
use std::collections::HashMap;

use typemap::Key;
use utils::typemap::Key;
use regex::Captures;

pub struct Parameters {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/utils/mod.rs
@@ -0,0 +1,3 @@


pub mod typemap;
112 changes: 112 additions & 0 deletions lib/src/utils/typemap.rs
@@ -0,0 +1,112 @@
// Extracted code from https://github.com/reem/rust-typemap, and adapted for shio usage
use std::collections::HashMap;
use std::any::{Any, TypeId};
use std::hash::{BuildHasherDefault, Hasher};
use std::ptr;

use unsafe_any::{UnsafeAny, UnsafeAnyExt};

#[derive(Default)]
pub struct TypeIdHasherValue {
value: u64,
}

impl Hasher for TypeIdHasherValue {
fn finish(&self) -> u64 {
self.value
}

fn write(&mut self, bytes: &[u8]) {
if bytes.len() != 8 {
panic!("unexpected len for typeid hash");
}

let buffer = &mut self.value as *mut u64;
let buffer = buffer as *mut u8;

let orig = bytes.as_ptr();

unsafe {
ptr::copy_nonoverlapping(orig, buffer, 8);
}
}
}

// exported only for avoid "private in public" error
#[doc(hidden)]
pub unsafe trait Implements<A: ?Sized + UnsafeAnyExt> {
fn into_object(self) -> Box<A>;
}

unsafe impl<T: UnsafeAny> Implements<UnsafeAny> for T {
fn into_object(self) -> Box<UnsafeAny> {
Box::new(self)
}
}

unsafe impl<T: UnsafeAny + Send + Sync> Implements<(UnsafeAny + Send + Sync)> for T {
fn into_object(self) -> Box<UnsafeAny + Send + Sync> {
Box::new(self)
}
}

#[derive(Default, Debug)]
pub struct TypeMap<A: ?Sized = UnsafeAny>
where
A: UnsafeAnyExt,
{
data: HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasherValue>>,
}

impl TypeMap {
pub fn new() -> TypeMap {
TypeMap::custom()
}
}

/// This trait defines the relationship between keys and values in a `TypeMap`.
///
/// It is implemented for Keys, with a phantom associated type for the values.
pub trait Key: Any {
/// The value type associated with this key type.
type Value: Any;
}

#[cfg(feature = "nightly")]
default impl<T: 'static> Key for T {
type Value = T;
}

impl<A: UnsafeAnyExt + ?Sized> TypeMap<A> {
/// Create a new, empty TypeMap.
///
/// Can be used with any `A` parameter; `new` is specialized to get around
/// the required type annotations when using this function.
pub fn custom() -> TypeMap<A> {
TypeMap {
data: HashMap::default(),
}
}

/// Insert a value into the map with a specified key type.
pub fn insert<K: Key>(&mut self, val: K::Value) -> Option<K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.insert(TypeId::of::<K>(), val.into_object())
.map(|v| unsafe { *v.downcast_unchecked::<K::Value>() })
}

/// Find a value in the map and get a reference to it.
pub fn get<K: Key>(&self) -> Option<&K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.get(&TypeId::of::<K>())
.map(|v| unsafe { v.downcast_ref_unchecked::<K::Value>() })
}
}

pub type ShareMap = TypeMap<UnsafeAny + Sync + Send>;