<commit_before>use std::collections::HashMap;
use std::marker;

use Message;

use descriptor::DescriptorProto;
use descriptor::FileDescriptorProto;

use descriptorx::find_message_by_rust_name;

use reflect::accessor::FieldAccessor;
use reflect::FieldDescriptor;
use reflect::reflect_deep_eq::ReflectDeepEq;

trait MessageFactory : Send + Sync + 'static {
    fn new_instance(&self) -> Box<Message>;
    fn default_instance(&self) -> &Message;
    fn clone(&self, message: &Message) -> Box<Message>;
    fn eq(&self, a: &Message, b: &Message) -> bool;
}

struct MessageFactoryImpl<M>(marker::PhantomData<M>);

impl<M> MessageFactory for MessageFactoryImpl<M>
    where M : 'static + Message + Default + Clone + PartialEq
{
    fn new_instance(&self) -> Box<Message> {
        let m: M = Default::default();
        Box::new(m)
    }

    fn default_instance(&self) -> &Message {
        M::default_instance() as &Message
    }

    fn clone(&self, message: &Message) -> Box<Message> {
        let m: &M = message.as_any().downcast_ref().expect("wrong message type");
        Box::new(m.clone())
    }

    fn eq(&self, a: &Message, b: &Message) -> bool {
        let a: &M = a.as_any().downcast_ref().expect("wrong message type");
        let b: &M = b.as_any().downcast_ref().expect("wrong message type");
        a == b
    }
}

pub struct MessageDescriptor {
    full_name: String,
    file_descriptor_proto: &'static FileDescriptorProto,
    proto: &'static DescriptorProto,
    factory: &'static MessageFactory,
    fields: Vec<FieldDescriptor>,

    index_by_name: HashMap<String, usize>,
    index_by_name_or_json_name: HashMap<String, usize>,
    index_by_number: HashMap<u32, usize>,
}

impl MessageDescriptor {
    pub fn for_type<M : Message>() -> &'static MessageDescriptor {
        M::descriptor_static()
    }

    pub fn new<M : 'static + Message + Default + Clone + PartialEq>(
        rust_name: &'static str,
        fields: Vec<FieldAccessor>,
        file_descriptor_proto: &'static FileDescriptorProto,
    ) -> MessageDescriptor {
        let proto = find_message_by_rust_name(file_descriptor_proto, rust_name);

        let mut field_proto_by_name = HashMap::new();
        for field_proto in proto.message.get_field() {
            field_proto_by_name.insert(field_proto.get_name(), field_proto);
        }

        let mut index_by_name = HashMap::new();
        let mut index_by_name_or_json_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, f) in proto.message.get_field().iter().enumerate() {
            assert!(index_by_number.insert(f.get_number() as u32, i).is_none());
            assert!(index_by_name.insert(f.get_name().to_owned(), i).is_none());
            assert!(index_by_name_or_json_name.insert(f.get_name().to_owned(), i).is_none());
            if f.get_json_name() != f.get_name() {
                let json_name = f.get_json_name().to_owned();
                assert!(index_by_name_or_json_name.insert(json_name, i).is_none());
            }
        }

        let mut full_name = file_descriptor_proto.get_package().to_string();
        if full_name.len() > 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.message.get_name());

        MessageDescriptor {
            full_name,
            proto: proto.message,
            factory: &MessageFactoryImpl(marker::PhantomData::<M>),
            fields: fields
                .into_iter()
                .map(|f| {
                    let proto = *field_proto_by_name.get(f.name).unwrap();
                    FieldDescriptor::new(f, proto)
                })
                .collect(),
            index_by_name,
            index_by_name_or_json_name,
            index_by_number,
            file_descriptor_proto,
        }
    }

    pub fn file_descriptor_proto(&self) -> &FileDescriptorProto {
        self.file_descriptor_proto
    }

    /// New empty message
    pub fn new_instance(&self) -> Box<Message> {
        self.factory.new_instance()
    }

    /// Shared immutable empty message
    pub fn default_instance(&self) -> &Message {
        self.factory.default_instance()
    }

    /// Clone a message
    pub fn clone(&self, message: &Message) -> Box<Message> {
        self.factory.clone(message)
    }

    /// Check if two messages equal.
    ///
    /// Panic is any message has different type than this descriptor.
    pub fn eq(&self, a: &Message, b: &Message) -> bool {
        self.factory.eq(a, b)
    }

    /// Similar to `eq`, but considers `NaN` values equal.
    ///
    /// Panics is any message has different type than this descriptor.
    pub fn deep_eq(&self, a: &Message, b: &Message) -> bool {
        // Explicitly force panic even if field list is empty
        assert_eq!(self as *const MessageDescriptor, a.descriptor() as *const MessageDescriptor);
        assert_eq!(self as *const MessageDescriptor, b.descriptor() as *const MessageDescriptor);

        for field in self.fields() {
            let af = field.get_reflect(a);
            let bf = field.get_reflect(b);
            if !af.reflect_deep_eq(&bf) {
                return false;
            }
        }
        true
    }

    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    pub fn fields<'a>(&'a self) -> &'a [FieldDescriptor] {
        &self.fields
    }

    /// Find message field by field name
    pub fn field_by_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.fields[index])
    }

    /// Find message field by field name or field JSON name
    pub fn field_by_name_or_json_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_name_or_json_name.get(name)?;
        Some(&self.fields[index])
    }

    /// Find message field by field name
    pub fn field_by_number<'a>(&'a self, number: u32) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.fields[index])
    }

    pub fn cast<M : 'static>(&self, message: Box<Message>) -> Result<M, Box<Message>> {
        message.downcast_box::<M>().map(|m| *m)
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for MessageDescriptor {
    fn eq(&self, other: &MessageDescriptor) -> bool {
        self as *const MessageDescriptor == other as *const MessageDescriptor
    }
}
<commit_msg>Fix codegen-pure JSON tests<commit_after>use std::collections::HashMap;
use std::marker;

use Message;

use descriptor::DescriptorProto;
use descriptor::FileDescriptorProto;

use descriptorx::find_message_by_rust_name;

use reflect::accessor::FieldAccessor;
use reflect::FieldDescriptor;
use reflect::reflect_deep_eq::ReflectDeepEq;

use json;

trait MessageFactory : Send + Sync + 'static {
    fn new_instance(&self) -> Box<Message>;
    fn default_instance(&self) -> &Message;
    fn clone(&self, message: &Message) -> Box<Message>;
    fn eq(&self, a: &Message, b: &Message) -> bool;
}

struct MessageFactoryImpl<M>(marker::PhantomData<M>);

impl<M> MessageFactory for MessageFactoryImpl<M>
    where M : 'static + Message + Default + Clone + PartialEq
{
    fn new_instance(&self) -> Box<Message> {
        let m: M = Default::default();
        Box::new(m)
    }

    fn default_instance(&self) -> &Message {
        M::default_instance() as &Message
    }

    fn clone(&self, message: &Message) -> Box<Message> {
        let m: &M = message.as_any().downcast_ref().expect("wrong message type");
        Box::new(m.clone())
    }

    fn eq(&self, a: &Message, b: &Message) -> bool {
        let a: &M = a.as_any().downcast_ref().expect("wrong message type");
        let b: &M = b.as_any().downcast_ref().expect("wrong message type");
        a == b
    }
}

pub struct MessageDescriptor {
    full_name: String,
    file_descriptor_proto: &'static FileDescriptorProto,
    proto: &'static DescriptorProto,
    factory: &'static MessageFactory,
    fields: Vec<FieldDescriptor>,

    index_by_name: HashMap<String, usize>,
    index_by_name_or_json_name: HashMap<String, usize>,
    index_by_number: HashMap<u32, usize>,
}

impl MessageDescriptor {
    pub fn for_type<M : Message>() -> &'static MessageDescriptor {
        M::descriptor_static()
    }

    pub fn new<M : 'static + Message + Default + Clone + PartialEq>(
        rust_name: &'static str,
        fields: Vec<FieldAccessor>,
        file_descriptor_proto: &'static FileDescriptorProto,
    ) -> MessageDescriptor {
        let proto = find_message_by_rust_name(file_descriptor_proto, rust_name);

        let mut field_proto_by_name = HashMap::new();
        for field_proto in proto.message.get_field() {
            field_proto_by_name.insert(field_proto.get_name(), field_proto);
        }

        let mut index_by_name = HashMap::new();
        let mut index_by_name_or_json_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, f) in proto.message.get_field().iter().enumerate() {
            assert!(index_by_number.insert(f.get_number() as u32, i).is_none());
            assert!(index_by_name.insert(f.get_name().to_owned(), i).is_none());
            assert!(index_by_name_or_json_name.insert(f.get_name().to_owned(), i).is_none());

            let json_name = json::json_name(f.get_name());

            if !f.get_json_name().is_empty() {
                assert_eq!(json_name, f.get_json_name());
            }

            if json_name != f.get_name() {
                assert!(index_by_name_or_json_name.insert(json_name, i).is_none());
            }
        }

        let mut full_name = file_descriptor_proto.get_package().to_string();
        if full_name.len() > 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.message.get_name());

        MessageDescriptor {
            full_name,
            proto: proto.message,
            factory: &MessageFactoryImpl(marker::PhantomData::<M>),
            fields: fields
                .into_iter()
                .map(|f| {
                    let proto = *field_proto_by_name.get(f.name).unwrap();
                    FieldDescriptor::new(f, proto)
                })
                .collect(),
            index_by_name,
            index_by_name_or_json_name,
            index_by_number,
            file_descriptor_proto,
        }
    }

    pub fn file_descriptor_proto(&self) -> &FileDescriptorProto {
        self.file_descriptor_proto
    }

    /// New empty message
    pub fn new_instance(&self) -> Box<Message> {
        self.factory.new_instance()
    }

    /// Shared immutable empty message
    pub fn default_instance(&self) -> &Message {
        self.factory.default_instance()
    }

    /// Clone a message
    pub fn clone(&self, message: &Message) -> Box<Message> {
        self.factory.clone(message)
    }

    /// Check if two messages equal.
    ///
    /// Panic is any message has different type than this descriptor.
    pub fn eq(&self, a: &Message, b: &Message) -> bool {
        self.factory.eq(a, b)
    }

    /// Similar to `eq`, but considers `NaN` values equal.
    ///
    /// Panics is any message has different type than this descriptor.
    pub fn deep_eq(&self, a: &Message, b: &Message) -> bool {
        // Explicitly force panic even if field list is empty
        assert_eq!(self as *const MessageDescriptor, a.descriptor() as *const MessageDescriptor);
        assert_eq!(self as *const MessageDescriptor, b.descriptor() as *const MessageDescriptor);

        for field in self.fields() {
            let af = field.get_reflect(a);
            let bf = field.get_reflect(b);
            if !af.reflect_deep_eq(&bf) {
                return false;
            }
        }
        true
    }

    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    pub fn fields<'a>(&'a self) -> &'a [FieldDescriptor] {
        &self.fields
    }

    /// Find message field by field name
    pub fn field_by_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.fields[index])
    }

    /// Find message field by field name or field JSON name
    pub fn field_by_name_or_json_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_name_or_json_name.get(name)?;
        Some(&self.fields[index])
    }

    /// Find message field by field name
    pub fn field_by_number<'a>(&'a self, number: u32) -> Option<&'a FieldDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.fields[index])
    }

    pub fn cast<M : 'static>(&self, message: Box<Message>) -> Result<M, Box<Message>> {
        message.downcast_box::<M>().map(|m| *m)
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for MessageDescriptor {
    fn eq(&self, other: &MessageDescriptor) -> bool {
        self as *const MessageDescriptor == other as *const MessageDescriptor
    }
}
<|endoftext|>


<commit_before>//! For path segment extractor documentation, see [`Path`].

use std::sync::Arc;

use actix_router::PathDeserializer;
use actix_utils::future::{ready, Ready};
use derive_more::{AsRef, Deref, DerefMut, Display, From};
use serde::de;

use crate::{
    dev::Payload,
    error::{Error, ErrorNotFound, PathError},
    web::Data,
    FromRequest, HttpRequest,
};

/// Extract typed data from request path segments.
///
/// Use [`PathConfig`] to configure extraction option.
///
/// Unlike, [`HttpRequest::match_info`], this extractor will fully percent-decode dynamic segments,
/// including `/`, `%`, and `+`.
///
/// # Examples
/// ```
/// use actix_web::{get, web};
///
/// // extract path info from "/{name}/{count}/index.html" into tuple
/// // {name}  - deserialize a String
/// // {count} - deserialize a u32
/// #[get("/{name}/{count}/index.html")]
/// async fn index(path: web::Path<(String, u32)>) -> String {
///     let (name, count) = path.into_inner();
///     format!("Welcome {}! {}", name, count)
/// }
/// ```
///
/// Path segments also can be deserialized into any type that implements [`serde::Deserialize`].
/// Path segment labels will be matched with struct field names.
///
/// ```
/// use actix_web::{get, web};
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Info {
///     name: String,
/// }
///
/// // extract `Info` from a path using serde
/// #[get("/{name}")]
/// async fn index(info: web::Path<Info>) -> String {
///     format!("Welcome {}!", info.name)
/// }
/// ```
#[derive(
    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut, AsRef, Display, From,
)]
pub struct Path<T>(T);

impl<T> Path<T> {
    /// Unwrap into inner `T` value.
    pub fn into_inner(self) -> T {
        self.0
    }
}

/// See [here](#Examples) for example of usage as an extractor.
impl<T> FromRequest for Path<T>
where
    T: de::DeserializeOwned,
{
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let error_handler = req
            .app_data::<PathConfig>()
            .or_else(|| req.app_data::<Data<PathConfig>>().map(Data::get_ref))
            .and_then(|c| c.err_handler.clone());

        ready(
            de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
                .map(Path)
                .map_err(move |err| {
                    log::debug!(
                        "Failed during Path extractor deserialization. \
                         Request path: {:?}",
                        req.path()
                    );

                    if let Some(error_handler) = error_handler {
                        let e = PathError::Deserialize(err);
                        (error_handler)(e, req)
                    } else {
                        ErrorNotFound(err)
                    }
                }),
        )
    }
}

/// Path extractor configuration
///
/// ```
/// use actix_web::web::PathConfig;
/// use actix_web::{error, web, App, FromRequest, HttpResponse};
/// use serde::Deserialize;
///
/// #[derive(Deserialize, Debug)]
/// enum Folder {
///     #[serde(rename = "inbox")]
///     Inbox,
///
///     #[serde(rename = "outbox")]
///     Outbox,
/// }
///
/// // deserialize `Info` from request's path
/// async fn index(folder: web::Path<Folder>) -> String {
///     format!("Selected folder: {:?}!", folder)
/// }
///
/// let app = App::new().service(
///     web::resource("/messages/{folder}")
///         .app_data(PathConfig::default().error_handler(|err, req| {
///             error::InternalError::from_response(
///                 err,
///                 HttpResponse::Conflict().into(),
///             )
///             .into()
///         }))
///         .route(web::post().to(index)),
/// );
/// ```
#[derive(Clone, Default)]
pub struct PathConfig {
    err_handler: Option<Arc<dyn Fn(PathError, &HttpRequest) -> Error + Send + Sync>>,
}

impl PathConfig {
    /// Set custom error handler.
    pub fn error_handler<F>(mut self, f: F) -> Self
    where
        F: Fn(PathError, &HttpRequest) -> Error + Send + Sync + 'static,
    {
        self.err_handler = Some(Arc::new(f));
        self
    }
}

#[cfg(test)]
mod tests {
    use actix_router::ResourceDef;
    use derive_more::Display;
    use serde::Deserialize;

    use super::*;
    use crate::test::TestRequest;
    use crate::{error, http, HttpResponse};

    #[derive(Deserialize, Debug, Display)]
    #[display(fmt = "MyStruct({}, {})", key, value)]
    struct MyStruct {
        key: String,
        value: String,
    }

    #[derive(Deserialize)]
    struct Test2 {
        key: String,
        value: u32,
    }

    #[actix_rt::test]
    async fn test_extract_path_single() {
        let resource = ResourceDef::new("/{value}/");

        let mut req = TestRequest::with_uri("/32/").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        assert_eq!(*Path::<i8>::from_request(&req, &mut pl).await.unwrap(), 32);
        assert!(Path::<MyStruct>::from_request(&req, &mut pl).await.is_err());
    }

    #[actix_rt::test]
    async fn test_tuple_extract() {
        let resource = ResourceDef::new("/{key}/{value}/");

        let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let (Path(res),) = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(res.0, "name");
        assert_eq!(res.1, "user1");

        let (Path(a), Path(b)) =
            <(Path<(String, String)>, Path<(String, String)>)>::from_request(&req, &mut pl)
                .await
                .unwrap();
        assert_eq!(a.0, "name");
        assert_eq!(a.1, "user1");
        assert_eq!(b.0, "name");
        assert_eq!(b.1, "user1");

        let () = <()>::from_request(&req, &mut pl).await.unwrap();
    }

    #[actix_rt::test]
    async fn test_request_extract() {
        let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();

        let resource = ResourceDef::new("/{key}/{value}/");
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let mut s = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(s.key, "name");
        assert_eq!(s.value, "user1");
        s.value = "user2".to_string();
        assert_eq!(s.value, "user2");
        assert_eq!(
            format!("{}, {:?}", s, s),
            "MyStruct(name, user2), Path(MyStruct { key: \"name\", value: \"user2\" })"
        );
        let s = s.into_inner();
        assert_eq!(s.value, "user2");

        let Path(s) = Path::<(String, String)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(s.0, "name");
        assert_eq!(s.1, "user1");

        let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
        let resource = ResourceDef::new("/{key}/{value}/");
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(s.as_ref().key, "name");
        assert_eq!(s.value, 32);

        let Path(s) = Path::<(String, u8)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(s.0, "name");
        assert_eq!(s.1, 32);

        let res = Path::<Vec<String>>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(res[0], "name".to_owned());
        assert_eq!(res[1], "32".to_owned());
    }

    #[actix_rt::test]
    async fn paths_decoded() {
        let resource = ResourceDef::new("/{key}/{value}");
        let mut req = TestRequest::with_uri("/na%2Bme/us%2Fer%254%32").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let path_items = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(path_items.key, "na+me");
        assert_eq!(path_items.value, "us/er%42");
        assert_eq!(req.match_info().as_str(), "/na%2Bme/us%2Fer%2542");
    }

    #[actix_rt::test]
    async fn test_custom_err_handler() {
        let (req, mut pl) = TestRequest::with_uri("/name/user1/")
            .app_data(PathConfig::default().error_handler(|err, _| {
                error::InternalError::from_response(err, HttpResponse::Conflict().finish())
                    .into()
            }))
            .to_http_parts();

        let s = Path::<(usize,)>::from_request(&req, &mut pl)
            .await
            .unwrap_err();
        let res = HttpResponse::from_error(s);

        assert_eq!(res.status(), http::StatusCode::CONFLICT);
    }
}
<commit_msg>Remove clone implementation for `Path` (#2639)<commit_after>//! For path segment extractor documentation, see [`Path`].

use std::sync::Arc;

use actix_router::PathDeserializer;
use actix_utils::future::{ready, Ready};
use derive_more::{AsRef, Deref, DerefMut, Display, From};
use serde::de;

use crate::{
    dev::Payload,
    error::{Error, ErrorNotFound, PathError},
    web::Data,
    FromRequest, HttpRequest,
};

/// Extract typed data from request path segments.
///
/// Use [`PathConfig`] to configure extraction option.
///
/// Unlike, [`HttpRequest::match_info`], this extractor will fully percent-decode dynamic segments,
/// including `/`, `%`, and `+`.
///
/// # Examples
/// ```
/// use actix_web::{get, web};
///
/// // extract path info from "/{name}/{count}/index.html" into tuple
/// // {name}  - deserialize a String
/// // {count} - deserialize a u32
/// #[get("/{name}/{count}/index.html")]
/// async fn index(path: web::Path<(String, u32)>) -> String {
///     let (name, count) = path.into_inner();
///     format!("Welcome {}! {}", name, count)
/// }
/// ```
///
/// Path segments also can be deserialized into any type that implements [`serde::Deserialize`].
/// Path segment labels will be matched with struct field names.
///
/// ```
/// use actix_web::{get, web};
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Info {
///     name: String,
/// }
///
/// // extract `Info` from a path using serde
/// #[get("/{name}")]
/// async fn index(info: web::Path<Info>) -> String {
///     format!("Welcome {}!", info.name)
/// }
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut, AsRef, Display, From)]
pub struct Path<T>(T);

impl<T> Path<T> {
    /// Unwrap into inner `T` value.
    pub fn into_inner(self) -> T {
        self.0
    }
}

/// See [here](#Examples) for example of usage as an extractor.
impl<T> FromRequest for Path<T>
where
    T: de::DeserializeOwned,
{
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let error_handler = req
            .app_data::<PathConfig>()
            .or_else(|| req.app_data::<Data<PathConfig>>().map(Data::get_ref))
            .and_then(|c| c.err_handler.clone());

        ready(
            de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
                .map(Path)
                .map_err(move |err| {
                    log::debug!(
                        "Failed during Path extractor deserialization. \
                         Request path: {:?}",
                        req.path()
                    );

                    if let Some(error_handler) = error_handler {
                        let e = PathError::Deserialize(err);
                        (error_handler)(e, req)
                    } else {
                        ErrorNotFound(err)
                    }
                }),
        )
    }
}

/// Path extractor configuration
///
/// ```
/// use actix_web::web::PathConfig;
/// use actix_web::{error, web, App, FromRequest, HttpResponse};
/// use serde::Deserialize;
///
/// #[derive(Deserialize, Debug)]
/// enum Folder {
///     #[serde(rename = "inbox")]
///     Inbox,
///
///     #[serde(rename = "outbox")]
///     Outbox,
/// }
///
/// // deserialize `Info` from request's path
/// async fn index(folder: web::Path<Folder>) -> String {
///     format!("Selected folder: {:?}!", folder)
/// }
///
/// let app = App::new().service(
///     web::resource("/messages/{folder}")
///         .app_data(PathConfig::default().error_handler(|err, req| {
///             error::InternalError::from_response(
///                 err,
///                 HttpResponse::Conflict().into(),
///             )
///             .into()
///         }))
///         .route(web::post().to(index)),
/// );
/// ```
#[derive(Clone, Default)]
pub struct PathConfig {
    err_handler: Option<Arc<dyn Fn(PathError, &HttpRequest) -> Error + Send + Sync>>,
}

impl PathConfig {
    /// Set custom error handler.
    pub fn error_handler<F>(mut self, f: F) -> Self
    where
        F: Fn(PathError, &HttpRequest) -> Error + Send + Sync + 'static,
    {
        self.err_handler = Some(Arc::new(f));
        self
    }
}

#[cfg(test)]
mod tests {
    use actix_router::ResourceDef;
    use derive_more::Display;
    use serde::Deserialize;

    use super::*;
    use crate::test::TestRequest;
    use crate::{error, http, HttpResponse};

    #[derive(Deserialize, Debug, Display)]
    #[display(fmt = "MyStruct({}, {})", key, value)]
    struct MyStruct {
        key: String,
        value: String,
    }

    #[derive(Deserialize)]
    struct Test2 {
        key: String,
        value: u32,
    }

    #[actix_rt::test]
    async fn test_extract_path_single() {
        let resource = ResourceDef::new("/{value}/");

        let mut req = TestRequest::with_uri("/32/").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        assert_eq!(*Path::<i8>::from_request(&req, &mut pl).await.unwrap(), 32);
        assert!(Path::<MyStruct>::from_request(&req, &mut pl).await.is_err());
    }

    #[actix_rt::test]
    async fn test_tuple_extract() {
        let resource = ResourceDef::new("/{key}/{value}/");

        let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let (Path(res),) = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(res.0, "name");
        assert_eq!(res.1, "user1");

        let (Path(a), Path(b)) =
            <(Path<(String, String)>, Path<(String, String)>)>::from_request(&req, &mut pl)
                .await
                .unwrap();
        assert_eq!(a.0, "name");
        assert_eq!(a.1, "user1");
        assert_eq!(b.0, "name");
        assert_eq!(b.1, "user1");

        let () = <()>::from_request(&req, &mut pl).await.unwrap();
    }

    #[actix_rt::test]
    async fn test_request_extract() {
        let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();

        let resource = ResourceDef::new("/{key}/{value}/");
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let mut s = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(s.key, "name");
        assert_eq!(s.value, "user1");
        s.value = "user2".to_string();
        assert_eq!(s.value, "user2");
        assert_eq!(
            format!("{}, {:?}", s, s),
            "MyStruct(name, user2), Path(MyStruct { key: \"name\", value: \"user2\" })"
        );
        let s = s.into_inner();
        assert_eq!(s.value, "user2");

        let Path(s) = Path::<(String, String)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(s.0, "name");
        assert_eq!(s.1, "user1");

        let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
        let resource = ResourceDef::new("/{key}/{value}/");
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(s.as_ref().key, "name");
        assert_eq!(s.value, 32);

        let Path(s) = Path::<(String, u8)>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(s.0, "name");
        assert_eq!(s.1, 32);

        let res = Path::<Vec<String>>::from_request(&req, &mut pl)
            .await
            .unwrap();
        assert_eq!(res[0], "name".to_owned());
        assert_eq!(res[1], "32".to_owned());
    }

    #[actix_rt::test]
    async fn paths_decoded() {
        let resource = ResourceDef::new("/{key}/{value}");
        let mut req = TestRequest::with_uri("/na%2Bme/us%2Fer%254%32").to_srv_request();
        resource.capture_match_info(req.match_info_mut());

        let (req, mut pl) = req.into_parts();
        let path_items = Path::<MyStruct>::from_request(&req, &mut pl).await.unwrap();
        assert_eq!(path_items.key, "na+me");
        assert_eq!(path_items.value, "us/er%42");
        assert_eq!(req.match_info().as_str(), "/na%2Bme/us%2Fer%2542");
    }

    #[actix_rt::test]
    async fn test_custom_err_handler() {
        let (req, mut pl) = TestRequest::with_uri("/name/user1/")
            .app_data(PathConfig::default().error_handler(|err, _| {
                error::InternalError::from_response(err, HttpResponse::Conflict().finish())
                    .into()
            }))
            .to_http_parts();

        let s = Path::<(usize,)>::from_request(&req, &mut pl)
            .await
            .unwrap_err();
        let res = HttpResponse::from_error(s);

        assert_eq!(res.status(), http::StatusCode::CONFLICT);
    }
}
<|endoftext|>


<commit_before>use content::content_task::global_content;
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache, CacheableWrapper};
use dom::bindings::codegen::DOMParserBinding;
use dom::document::Document;
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
use dom::node::Node;
use dom::window::Window;

pub struct DOMParser {
    owner: @mut Window, //XXXjdm Document instead?
    wrapper: WrapperCache
}

pub impl DOMParser {
    fn new(owner: @mut Window) -> @mut DOMParser {
        let parser = @mut DOMParser {
            owner: owner,
            wrapper: WrapperCache::new()
        };
        let cx = global_content().compartment.get().cx.ptr;
        let cache = owner.get_wrappercache();
        let scope = cache.get_wrapper();
        parser.wrap_object_shared(cx, scope);
        parser
    }

    fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
        DOMParser::new(owner)
    }

    fn ParseFromString(&self, _s: DOMString, _type_: DOMParserBinding::SupportedType, _rv: &mut ErrorResult) -> @mut Document {
        let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
        let root = unsafe { Node::as_abstract_node(root) };
        Document(root, None)
    }
}<commit_msg>Fix code style in DOMParser<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use content::content_task::global_content;
use dom::bindings::codegen::DOMParserBinding;
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache, CacheableWrapper};
use dom::document::Document;
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
use dom::node::Node;
use dom::window::Window;

pub struct DOMParser {
    owner: @mut Window, //XXXjdm Document instead?
    wrapper: WrapperCache
}

impl DOMParser {
    pub fn new(owner: @mut Window) -> @mut DOMParser {
        let parser = @mut DOMParser {
            owner: owner,
            wrapper: WrapperCache::new()
        };

        let cx = global_content().compartment.get().cx.ptr;
        let cache = owner.get_wrappercache();
        let scope = cache.get_wrapper();
        parser.wrap_object_shared(cx, scope);
        parser
    }

    pub fn Constructor(owner: @mut Window, _rv: &mut ErrorResult) -> @mut DOMParser {
        DOMParser::new(owner)
    }

    pub fn ParseFromString(&self,
                           _s: DOMString,
                           _type: DOMParserBinding::SupportedType,
                           _rv: &mut ErrorResult)
                           -> @mut Document {
        unsafe {
            let root = ~HTMLHtmlElement {
                parent: Element::new(HTMLHtmlElementTypeId, ~"html")
            };

            let root = Node::as_abstract_node(root);
            Document(root, None)
        }
    }
}

<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::FileName;

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let function_span = self.mir.span;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
            // In order to have a good line stepping behavior in debugger, we overwrite debug
            // locations of macro expansions with that of the outermost expansion site
            // (unless the crate is being compiled with `-Z debug-macros`).
            let span = if !span.from_expansion() ||
                tcx.sess.opts.debugging_opts.debug_macros {
                span
            } else {
                // Walk up the macro expansion chain until we reach a non-expanded span.
                // We also stop at the function body level because no line stepping can occur
                // at the level above that.
                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
            };

            let loc = tcx.sess.source_map().lookup_char_pos(span.lo());

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &mut last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &loc.file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);
                line_program.row().file = file_id;
                last_file = Some(loc.file.clone());
            }

            line_program.row().line = loc.line as u64;
            line_program.row().column = loc.col.to_u32() as u64 + 1;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<commit_msg>Use byte offsets instead of char offsets in debuginfo<commit_after>use std::ffi::OsStr;
use std::path::{Component, Path};

use crate::prelude::*;

use rustc_span::{FileName, SourceFileAndLine};

use cranelift_codegen::binemit::CodeOffset;

use gimli::write::{
    Address, AttributeValue, FileId, LineProgram, LineString, LineStringTable, UnitEntryId,
};

// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
    let mut iter = path.components();
    let file_name = match iter.next_back() {
        Some(Component::Normal(p)) => p,
        component => {
            panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
        }
    };
    let parent = iter.as_path();
    (parent, file_name)
}

// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
    #[cfg(unix)] {
        use std::os::unix::ffi::OsStrExt;
        return path.as_bytes();
    }
    #[cfg(not(unix))] {
        return path.to_str().unwrap().as_bytes();
    }
}

fn line_program_add_file(
    line_program: &mut LineProgram,
    line_strings: &mut LineStringTable,
    file: &FileName,
) -> FileId {
    match file {
        FileName::Real(path) => {
            let (dir_path, file_name) = split_path_dir_and_file(path);
            let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
            let file_name = osstr_as_utf8_bytes(file_name);

            let dir_id = if !dir_name.is_empty() {
                let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
                line_program.add_directory(dir_name)
            } else {
                line_program.default_directory()
            };
            let file_name = LineString::new(
                file_name,
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(file_name, dir_id, None)
        }
        // FIXME give more appropriate file names
        _ => {
            let dir_id = line_program.default_directory();
            let dummy_file_name = LineString::new(
                file.to_string().into_bytes(),
                line_program.encoding(),
                line_strings,
            );
            line_program.add_file(dummy_file_name, dir_id, None)
        }
    }
}

impl<'tcx> DebugContext<'tcx> {
    pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
        let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());

        let file_id = line_program_add_file(
            &mut self.dwarf.unit.line_program,
            &mut self.dwarf.line_strings,
            &loc.file.name,
        );

        let entry = self.dwarf.unit.get_mut(entry_id);

        entry.set(
            gimli::DW_AT_decl_file,
            AttributeValue::FileIndex(Some(file_id)),
        );
        entry.set(
            gimli::DW_AT_decl_line,
            AttributeValue::Udata(loc.line as u64),
        );
        // FIXME: probably omit this
        entry.set(
            gimli::DW_AT_decl_column,
            AttributeValue::Udata(loc.col.to_usize() as u64),
        );
    }
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(super) fn create_debug_lines(
        &mut self,
        context: &Context,
        isa: &dyn cranelift_codegen::isa::TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
    ) -> CodeOffset {
        let tcx = self.debug_context.tcx;

        let line_program = &mut self.debug_context.dwarf.unit.line_program;

        line_program.begin_sequence(Some(Address::Symbol {
            symbol: self.symbol,
            addend: 0,
        }));

        let encinfo = isa.encoding_info();
        let func = &context.func;
        let mut blocks = func.layout.blocks().collect::<Vec<_>>();
        blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase

        let line_strings = &mut self.debug_context.dwarf.line_strings;
        let function_span = self.mir.span;
        let mut last_file = None;
        let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
            // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
            // In order to have a good line stepping behavior in debugger, we overwrite debug
            // locations of macro expansions with that of the outermost expansion site
            // (unless the crate is being compiled with `-Z debug-macros`).
            let span = if !span.from_expansion() ||
                tcx.sess.opts.debugging_opts.debug_macros {
                span
            } else {
                // Walk up the macro expansion chain until we reach a non-expanded span.
                // We also stop at the function body level because no line stepping can occur
                // at the level above that.
                rustc_span::hygiene::walk_chain(span, function_span.ctxt())
            };

            let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
                Ok(SourceFileAndLine { sf: file, line }) => {
                    let line_pos = file.line_begin_pos(span.lo());

                    (file, u64::try_from(line).unwrap() + 1, u64::from((span.lo() - line_pos).to_u32()) + 1)
                }
                Err(file) => (file, 0, 0)
            };

            // line_program_add_file is very slow.
            // Optimize for the common case of the current file not being changed.
            let current_file_changed = if let Some(last_file) = &mut last_file {
                // If the allocations are not equal, then the files may still be equal, but that
                // is not a problem, as this is just an optimization.
                !Lrc::ptr_eq(last_file, &file)
            } else {
                true
            };
            if current_file_changed {
                let file_id = line_program_add_file(line_program, line_strings, &file.name);
                line_program.row().file = file_id;
                last_file = Some(file.clone());
            }

            line_program.row().line = line;
            line_program.row().column = col;
            line_program.generate_row();
        };

        let mut end = 0;
        for block in blocks {
            for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
                let srcloc = func.srclocs[inst];
                line_program.row().address_offset = offset as u64;
                if !srcloc.is_default() {
                    let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
                    create_row_for_span(line_program, source_info.span);
                } else {
                    create_row_for_span(line_program, self.mir.span);
                }
                end = offset + size;
            }
        }

        line_program.end_sequence(end as u64);

        let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
        entry.set(
            gimli::DW_AT_low_pc,
            AttributeValue::Address(Address::Symbol {
                symbol: self.symbol,
                addend: 0,
            }),
        );
        entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));

        self.debug_context
            .emit_location(self.entry_id, self.mir.span);

        end
    }
}
<|endoftext|>


<commit_before>extern crate gstreamer as gst;
extern crate gstreamer_app as gst_app;

extern crate byte_slice_cast;
use byte_slice_cast::AsSliceOf;

use std::i16;

use std::collections::vec_deque::VecDeque;

pub struct AudioBuffer {
    pub capacity: usize,
    pub sample_duration: u64,
    pub channels: usize,
    pub drain_size: usize,
    pub drain_duration: u64,

    pub first_sample_offset: usize,
    pub first_pts: u64,
    pub current_pts: u64,
    pub current_pts_relative: u64,
    pub last_pts: u64,
    pub duration: u64,
    pub samples: VecDeque<f64>,
}

impl AudioBuffer {
    pub fn new() -> Self {
        AudioBuffer {
            capacity: 0,
            sample_duration: 0,
            channels: 0,
            drain_size: 1,
            drain_duration: 0,

            first_sample_offset: 0,
            first_pts: 0,
            current_pts: 0,
            current_pts_relative: 0,
            last_pts: 0,
            duration: 0,
            samples: VecDeque::new(),
        }
    }

    pub fn initialize(&mut self, caps: &gst::Caps, size_duration: u64) {
        let structure = caps.get_structure(0)
            .expect("Couldn't get structure from audio caps");
        let rate = structure.get::<i32>("rate")
            .expect("Couldn't get rate from audio caps");

        // assert_eq!(format, S16);
        // assert_eq!(layout, Interleaved);

        let sample_duration = 1_000_000_000 / (rate as u64);
        let capacity = (size_duration / sample_duration) as usize;

        let drain_size = capacity / 5;

        self.capacity = capacity;
        self.sample_duration = sample_duration;
        self.channels =structure.get::<i32>("channels")
            .expect("Couldn't get channels from audio sample")
            as usize;
        self.drain_size = drain_size;
        self.drain_duration = (drain_size as u64) * sample_duration;

        self.first_sample_offset = 0;
        self.first_pts = 0;
        self.current_pts = 0;
        self.current_pts_relative = 0;
        self.last_pts = 0;
        self.duration = 0;

        let current_capacity = self.samples.capacity();
        if current_capacity < capacity {
            self.samples.reserve(capacity - current_capacity);
        }
    }

    pub fn set_first_pts(&mut self, pts: u64) {
        if self.samples.is_empty() {
            self.first_sample_offset = (pts / self.sample_duration) as usize;
            self.first_pts = pts;
            self.set_pts(pts);
            self.last_pts += pts;
        }
    }

    pub fn set_pts(&mut self, pts: u64) {
        self.current_pts = pts;
        self.current_pts_relative = pts - self.first_pts;
    }

    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        let buffer = sample.get_buffer()
            .expect("Couldn't get buffer from audio sample");

        let map = buffer.map_readable().unwrap();
        let incoming_samples = map.as_slice().as_slice_of::<i16>()
            .expect("Couldn't get audio samples as i16");

        if self.samples.len() + incoming_samples.len() > self.capacity
            && self.current_pts_relative > 2_000_000_000
        {   // buffer will reach capacity => drain a chunk of samples
            // only if we have 2 sec worse of samples in history
            self.samples.drain(..self.drain_size);
            self.first_sample_offset += self.drain_size;
            self.first_pts += self.drain_duration;
            self.current_pts_relative -= self.drain_duration;
            self.duration -= self.drain_duration;
        }

        // normalize samples in range 0f64..2f64 ready to render

        // FIXME: use gstreamer downmix
        // FIXME: select the channels using the position info
        // if more than 2 channels,
        // Use 75% for first 2 channels (assumes front left and front right)
        // Use 25% for the rest
        let (front_norm_factor, others_norm_factor, front_channels) =
            if self.channels > 2 {
                (
                    0.75f64 / 2f64 / (i16::MAX as f64),
                    0.25f64 / ((self.channels - 2) as f64) / (i16::MAX as f64),
                    2
                )
            } else {
                (
                    1f64 / (self.channels as f64) / (i16::MAX as f64),
                    0f64,
                    self.channels
                )
            };

        let mut norm_sample;
        let mut index = 0;
        while index < incoming_samples.len() {
            norm_sample = 0f64;

            for _ in 0..front_channels {
                norm_sample += incoming_samples[index] as f64 * front_norm_factor;
                index += 1;
            }
            for _ in front_channels..self.channels {
                norm_sample += incoming_samples[index] as f64 * others_norm_factor;
                index += 1;
            }
            self.samples.push_back(1f64 - norm_sample);
        };

        let duration = buffer.get_duration();
        self.last_pts += duration;
        self.duration += duration;
    }
}
<commit_msg>Remove magic constant from AudioBuffer drain (#19)<commit_after>extern crate gstreamer as gst;
extern crate gstreamer_app as gst_app;

extern crate byte_slice_cast;
use byte_slice_cast::AsSliceOf;

use std::i16;

use std::collections::vec_deque::VecDeque;

pub struct AudioBuffer {
    pub capacity: usize,
    pub sample_duration: u64,
    pub channels: usize,
    pub drain_size: usize,
    pub drain_duration: u64,

    pub first_sample_offset: usize,
    pub first_pts: u64,
    pub current_pts: u64,
    pub current_pts_relative: u64,
    pub last_pts: u64,
    pub duration: u64,
    pub samples: VecDeque<f64>,
}

impl AudioBuffer {
    pub fn new() -> Self {
        AudioBuffer {
            capacity: 0,
            sample_duration: 0,
            channels: 0,
            drain_size: 1,
            drain_duration: 0,

            first_sample_offset: 0,
            first_pts: 0,
            current_pts: 0,
            current_pts_relative: 0,
            last_pts: 0,
            duration: 0,
            samples: VecDeque::new(),
        }
    }

    pub fn initialize(&mut self, caps: &gst::Caps, size_duration: u64) {
        let structure = caps.get_structure(0)
            .expect("Couldn't get structure from audio caps");
        let rate = structure.get::<i32>("rate")
            .expect("Couldn't get rate from audio caps");

        // assert_eq!(format, S16);
        // assert_eq!(layout, Interleaved);

        let sample_duration = 1_000_000_000 / (rate as u64);
        let capacity = (size_duration / sample_duration) as usize;

        let drain_size = capacity / 5;

        self.capacity = capacity;
        self.sample_duration = sample_duration;
        self.channels =structure.get::<i32>("channels")
            .expect("Couldn't get channels from audio sample")
            as usize;
        self.drain_size = drain_size;
        self.drain_duration = (drain_size as u64) * sample_duration;

        self.first_sample_offset = 0;
        self.first_pts = 0;
        self.current_pts = 0;
        self.current_pts_relative = 0;
        self.last_pts = 0;
        self.duration = 0;

        let current_capacity = self.samples.capacity();
        if current_capacity < capacity {
            self.samples.reserve(capacity - current_capacity);
        }
    }

    pub fn set_first_pts(&mut self, pts: u64) {
        if self.samples.is_empty() {
            self.first_sample_offset = (pts / self.sample_duration) as usize;
            self.first_pts = pts;
            self.set_pts(pts);
            self.last_pts += pts;
        }
    }

    pub fn set_pts(&mut self, pts: u64) {
        self.current_pts = pts;
        self.current_pts_relative = pts - self.first_pts;
    }

    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        let buffer = sample.get_buffer()
            .expect("Couldn't get buffer from audio sample");

        let map = buffer.map_readable().unwrap();
        let incoming_samples = map.as_slice().as_slice_of::<i16>()
            .expect("Couldn't get audio samples as i16");

        if self.samples.len() + incoming_samples.len() > self.capacity
            && self.current_pts_relative > 2 * self.drain_duration
        {   // buffer will reach capacity => drain a chunk of samples
            // only if we have samples in history
            self.samples.drain(..self.drain_size);
            self.first_sample_offset += self.drain_size;
            self.first_pts += self.drain_duration;
            self.current_pts_relative -= self.drain_duration;
            self.duration -= self.drain_duration;
        }

        // normalize samples in range 0f64..2f64 ready to render

        // FIXME: use gstreamer downmix
        // FIXME: select the channels using the position info
        // if more than 2 channels,
        // Use 75% for first 2 channels (assumes front left and front right)
        // Use 25% for the rest
        let (front_norm_factor, others_norm_factor, front_channels) =
            if self.channels > 2 {
                (
                    0.75f64 / 2f64 / (i16::MAX as f64),
                    0.25f64 / ((self.channels - 2) as f64) / (i16::MAX as f64),
                    2
                )
            } else {
                (
                    1f64 / (self.channels as f64) / (i16::MAX as f64),
                    0f64,
                    self.channels
                )
            };

        let mut norm_sample;
        let mut index = 0;
        while index < incoming_samples.len() {
            norm_sample = 0f64;

            for _ in 0..front_channels {
                norm_sample += incoming_samples[index] as f64 * front_norm_factor;
                index += 1;
            }
            for _ in front_channels..self.channels {
                norm_sample += incoming_samples[index] as f64 * others_norm_factor;
                index += 1;
            }
            self.samples.push_back(1f64 - norm_sample);
        };

        let duration = buffer.get_duration();
        self.last_pts += duration;
        self.duration += duration;
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for &'a str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&self.guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        CACHE
            .read()
            .unwrap()
            .guilds
            .values()
            .find(|guild| {
                guild.read().unwrap().members.values().any(|m| {
                    m.user.read().unwrap().id == self.user.read().unwrap().id &&
                    m.joined_at == self.joined_at
                })
            })
            .map(|guild| {
                guild
                    .read()
                    .unwrap()
                    .roles
                    .values()
                    .filter(|role| self.roles.contains(&role.id))
                    .cloned()
                    .collect()
            })
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<commit_msg>Optimize Member::roles<commit_after>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for &'a str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&self.guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        self
            .guild_id
            .find()
            .map(|g| g
                .read()
                .unwrap()
                .roles
                .values()
                .filter(|role| self.roles.contains(&role.id))
                .cloned()
                .collect())
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<|endoftext|>


<commit_before>// error-pattern:ran out of stack

// Test that the task fails after hiting the recursion limit

fn main() {
    main();
}<commit_msg>test: Prevent run-fail/too-much-recursion from being optimized to nothing<commit_after>// error-pattern:ran out of stack

// Test that the task fails after hiting the recursion limit

fn main() {
    log(debug, "don't optimize me out");
    main();
}<|endoftext|>


<commit_before>//! Auto-generate stub docs for the unstable book

#![deny(warnings)]

use tidy::features::{Feature, Features, collect_lib_features, collect_lang_features};
use tidy::unstable_book::{collect_unstable_feature_names, collect_unstable_book_section_file_names,
                          PATH_STR, LANG_FEATURES_DIR, LIB_FEATURES_DIR};
use std::collections::BTreeSet;
use std::io::Write;
use std::fs::{self, File};
use std::env;
use std::path::Path;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn generate_stub_issue(path: &Path, name: &str, issue: u32) {
    let mut file = t!(File::create(path));
    t!(file.write_fmt(format_args!(include_str!("stub-issue.md"),
                                   name = name,
                                   issue = issue)));
}

fn generate_stub_no_issue(path: &Path, name: &str) {
    let mut file = t!(File::create(path));
    t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"),
                                   name = name)));
}

fn set_to_summary_str(set: &BTreeSet<String>, dir: &str
) -> String {
    set
        .iter()
        .map(|ref n| format!("    - [{}]({}/{}.md)",
                                      n.replace('-', "_"),
                                      dir,
                                      n))
        .fold("".to_owned(), |s, a| s + &a + "\n")
}

fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) {
    let compiler_flags = collect_unstable_book_section_file_names(
        &path.join("src/compiler-flags"));

    let compiler_flags_str = set_to_summary_str(&compiler_flags,
                                                "compiler-flags");

    let unstable_lang_features = collect_unstable_feature_names(&lang_features);
    let unstable_lib_features = collect_unstable_feature_names(&lib_features);

    let lang_features_str = set_to_summary_str(&unstable_lang_features,
                                               "language-features");
    let lib_features_str = set_to_summary_str(&unstable_lib_features,
                                              "library-features");

    let mut file = t!(File::create(&path.join("src/SUMMARY.md")));
    t!(file.write_fmt(format_args!(include_str!("SUMMARY.md"),
                                   compiler_flags = compiler_flags_str,
                                   language_features = lang_features_str,
                                   library_features = lib_features_str)));

}

fn has_valid_tracking_issue(f: &Feature) -> bool {
    if let Some(n) = f.tracking_issue {
        if n > 0 {
            return true;
        }
    }
    false
}

fn generate_unstable_book_files(src :&Path, out: &Path, features :&Features) {
    let unstable_features = collect_unstable_feature_names(features);
    let unstable_section_file_names = collect_unstable_book_section_file_names(src);
    t!(fs::create_dir_all(&out));
    for feature_name in &unstable_features - &unstable_section_file_names {
        let feature_name_underscore = feature_name.replace('-', "_");
        let file_name = format!("{}.md", feature_name);
        let out_file_path = out.join(&file_name);
        let feature = &features[&feature_name_underscore];

        if has_valid_tracking_issue(&feature) {
            generate_stub_issue(&out_file_path,
                                &feature_name_underscore,
                                feature.tracking_issue.unwrap());
        } else {
            generate_stub_no_issue(&out_file_path, &feature_name_underscore);
        }
    }
}

fn copy_recursive(from: &Path, to: &Path) {
    for entry in t!(fs::read_dir(from)) {
        let e = t!(entry);
        let t = t!(e.metadata());
        let dest = &to.join(e.file_name());
        if t.is_file() {
            t!(fs::copy(&e.path(), dest));
        } else if t.is_dir() {
            t!(fs::create_dir_all(dest));
            copy_recursive(&e.path(), dest);
        }
    }
}

fn main() {
    let src_path_str = env::args_os().skip(1).next().expect("source path required");
    let dest_path_str = env::args_os().skip(2).next().expect("destination path required");
    let src_path = Path::new(&src_path_str);
    let dest_path = Path::new(&dest_path_str);

    let lang_features = collect_lang_features(src_path, &mut false);
    let lib_features = collect_lib_features(src_path).into_iter().filter(|&(ref name, _)| {
        !lang_features.contains_key(name)
    }).collect();

    let doc_src_path = src_path.join(PATH_STR);

    t!(fs::create_dir_all(&dest_path));

    generate_unstable_book_files(&doc_src_path.join(LANG_FEATURES_DIR),
                                 &dest_path.join(LANG_FEATURES_DIR),
                                 &lang_features);
    generate_unstable_book_files(&doc_src_path.join(LIB_FEATURES_DIR),
                                 &dest_path.join(LIB_FEATURES_DIR),
                                 &lib_features);

    copy_recursive(&doc_src_path, &dest_path);

    generate_summary(&dest_path, &lang_features, &lib_features);
}
<commit_msg>Update unstable book build to use NonZeroU32<commit_after>//! Auto-generate stub docs for the unstable book

#![deny(warnings)]

use tidy::features::{Features, collect_lib_features, collect_lang_features};
use tidy::unstable_book::{collect_unstable_feature_names, collect_unstable_book_section_file_names,
                          PATH_STR, LANG_FEATURES_DIR, LIB_FEATURES_DIR};
use std::collections::BTreeSet;
use std::io::Write;
use std::fs::{self, File};
use std::env;
use std::path::Path;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn generate_stub_issue(path: &Path, name: &str, issue: u32) {
    let mut file = t!(File::create(path));
    t!(file.write_fmt(format_args!(include_str!("stub-issue.md"),
                                   name = name,
                                   issue = issue)));
}

fn generate_stub_no_issue(path: &Path, name: &str) {
    let mut file = t!(File::create(path));
    t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"),
                                   name = name)));
}

fn set_to_summary_str(set: &BTreeSet<String>, dir: &str
) -> String {
    set
        .iter()
        .map(|ref n| format!("    - [{}]({}/{}.md)",
                                      n.replace('-', "_"),
                                      dir,
                                      n))
        .fold("".to_owned(), |s, a| s + &a + "\n")
}

fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) {
    let compiler_flags = collect_unstable_book_section_file_names(
        &path.join("src/compiler-flags"));

    let compiler_flags_str = set_to_summary_str(&compiler_flags,
                                                "compiler-flags");

    let unstable_lang_features = collect_unstable_feature_names(&lang_features);
    let unstable_lib_features = collect_unstable_feature_names(&lib_features);

    let lang_features_str = set_to_summary_str(&unstable_lang_features,
                                               "language-features");
    let lib_features_str = set_to_summary_str(&unstable_lib_features,
                                              "library-features");

    let mut file = t!(File::create(&path.join("src/SUMMARY.md")));
    t!(file.write_fmt(format_args!(include_str!("SUMMARY.md"),
                                   compiler_flags = compiler_flags_str,
                                   language_features = lang_features_str,
                                   library_features = lib_features_str)));

}

fn generate_unstable_book_files(src :&Path, out: &Path, features :&Features) {
    let unstable_features = collect_unstable_feature_names(features);
    let unstable_section_file_names = collect_unstable_book_section_file_names(src);
    t!(fs::create_dir_all(&out));
    for feature_name in &unstable_features - &unstable_section_file_names {
        let feature_name_underscore = feature_name.replace('-', "_");
        let file_name = format!("{}.md", feature_name);
        let out_file_path = out.join(&file_name);
        let feature = &features[&feature_name_underscore];

        if let Some(issue) = feature.tracking_issue {
            generate_stub_issue(&out_file_path,
                                &feature_name_underscore,
                                issue.get());
        } else {
            generate_stub_no_issue(&out_file_path, &feature_name_underscore);
        }
    }
}

fn copy_recursive(from: &Path, to: &Path) {
    for entry in t!(fs::read_dir(from)) {
        let e = t!(entry);
        let t = t!(e.metadata());
        let dest = &to.join(e.file_name());
        if t.is_file() {
            t!(fs::copy(&e.path(), dest));
        } else if t.is_dir() {
            t!(fs::create_dir_all(dest));
            copy_recursive(&e.path(), dest);
        }
    }
}

fn main() {
    let src_path_str = env::args_os().skip(1).next().expect("source path required");
    let dest_path_str = env::args_os().skip(2).next().expect("destination path required");
    let src_path = Path::new(&src_path_str);
    let dest_path = Path::new(&dest_path_str);

    let lang_features = collect_lang_features(src_path, &mut false);
    let lib_features = collect_lib_features(src_path).into_iter().filter(|&(ref name, _)| {
        !lang_features.contains_key(name)
    }).collect();

    let doc_src_path = src_path.join(PATH_STR);

    t!(fs::create_dir_all(&dest_path));

    generate_unstable_book_files(&doc_src_path.join(LANG_FEATURES_DIR),
                                 &dest_path.join(LANG_FEATURES_DIR),
                                 &lang_features);
    generate_unstable_book_files(&doc_src_path.join(LIB_FEATURES_DIR),
                                 &dest_path.join(LIB_FEATURES_DIR),
                                 &lib_features);

    copy_recursive(&doc_src_path, &dest_path);

    generate_summary(&dest_path, &lang_features, &lib_features);
}
<|endoftext|>