<commit_before>use std::fmt;
use std::io::Read;

use crate::descriptor::DescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::dynamic::DynamicMessage;
use crate::reflect::field::FieldDescriptorImpl;
use crate::reflect::file::index::FileIndexMessageEntry;
use crate::reflect::file::FileDescriptorImpl;
use crate::reflect::message::dynamic::DynamicMessageDescriptor;
use crate::reflect::message::generated::GeneratedMessageDescriptor;
use crate::reflect::message::index::MessageIndex;
use crate::reflect::reflect_eq::ReflectEq;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::EnumDescriptor;
use crate::reflect::FieldDescriptor;
use crate::reflect::FileDescriptor;
use crate::reflect::OneofDescriptor;
use crate::CodedInputStream;

pub(crate) mod dynamic;
pub(crate) mod generated;
pub(crate) mod index;
pub(crate) mod message_ref;
pub(crate) mod path;

/// Dynamic representation of message type.
///
/// Used for reflection.
#[derive(Clone, Eq, PartialEq)]
pub struct MessageDescriptor {
    file_descriptor: FileDescriptor,
    index: usize,
}

impl fmt::Display for MessageDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.full_name())
    }
}

impl fmt::Debug for MessageDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MessageDescriptor")
            // TODO: add smth
            .finish()
    }
}

impl MessageDescriptor {
    pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> MessageDescriptor {
        MessageDescriptor {
            file_descriptor,
            index,
        }
    }

    /// Get internal index.
    ///
    /// Only needed for codegen.
    #[doc(hidden)]
    pub fn index_in_file_for_codegen(&self) -> usize {
        self.index
    }

    /// Get underlying `DescriptorProto` object.
    pub fn proto(&self) -> &DescriptorProto {
        self.file_descriptor.message_proto(self.index)
    }

    /// Message name as specified in `.proto` file.
    pub fn name(&self) -> &str {
        self.proto().name()
    }

    /// Get enums declared in this message.
    pub fn enums(&self) -> impl Iterator<Item = EnumDescriptor> + '_ {
        let first_enum_index = self.index_entry().first_enum_index;
        self.proto()
            .enum_type
            .iter()
            .enumerate()
            .map(move |(i, _)| {
                EnumDescriptor::new(self.file_descriptor.clone(), first_enum_index + i)
            })
    }

    fn index_entry(&self) -> &FileIndexMessageEntry {
        self.file_descriptor.message_index_entry(self.index)
    }

    /// Get a message descriptor for given message type
    pub fn for_type<M: MessageFull>() -> MessageDescriptor {
        M::descriptor_static()
    }

    #[doc(hidden)]
    pub fn new_generated_2(file_descriptor: FileDescriptor, index: usize) -> MessageDescriptor {
        MessageDescriptor::new(file_descriptor, index)
    }

    /// Messages declared in this messages.
    pub fn nested_messages(&self) -> impl Iterator<Item = MessageDescriptor> + '_ {
        self.index_entry()
            .nested_messages
            .iter()
            .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), *i))
    }

    /// Get a message containing this message, or `None` if this message is declared at file level.
    pub fn enclosing_message(&self) -> Option<MessageDescriptor> {
        self.index_entry()
            .enclosing_message
            .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), i))
    }

    pub(crate) fn get_impl(&self) -> MessageDescriptorImplRef {
        match &self.file_descriptor.imp {
            FileDescriptorImpl::Generated(g) => {
                MessageDescriptorImplRef::Generated(&g.messages[self.index])
            }
            FileDescriptorImpl::Dynamic(d) => {
                MessageDescriptorImplRef::Dynamic(&d.messages[self.index])
            }
        }
    }

    /// [`FileDescriptor`] containing this message.
    pub fn file_descriptor(&self) -> &FileDescriptor {
        &self.file_descriptor
    }

    /// `FileDescriptorProto` containg this message type
    pub fn file_descriptor_proto(&self) -> &FileDescriptorProto {
        self.file_descriptor().proto()
    }

    /// This message descriptor is a map entry.
    pub fn is_map_entry(&self) -> bool {
        self.proto().options.get_or_default().map_entry()
    }

    fn assert_not_map_entry(&self) {
        assert!(
            !self.is_map_entry(),
            "message is map entry: {}",
            self.full_name()
        );
    }

    /// New empty message.
    ///
    /// # Panics
    ///
    /// If this message is a map entry message.
    pub fn new_instance(&self) -> Box<dyn MessageDyn> {
        self.assert_not_map_entry();
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.new_instance(),
            MessageDescriptorImplRef::Dynamic(..) => Box::new(DynamicMessage::new(self.clone())),
        }
    }

    /// Shared immutable empty message.
    ///
    /// Returns `None` for dynamic message.
    ///
    /// # Panics
    ///
    /// If this message is a map entry message.
    pub fn default_instance(&self) -> Option<&'static dyn MessageDyn> {
        self.assert_not_map_entry();
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => Some(g.non_map().factory.default_instance()),
            MessageDescriptorImplRef::Dynamic(..) => None,
        }
    }

    /// Clone a message
    pub(crate) fn clone_message(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn> {
        assert!(&message.descriptor_dyn() == self);
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.clone(message),
            MessageDescriptorImplRef::Dynamic(..) => {
                let message: &DynamicMessage = DynamicMessage::downcast_ref(message);
                Box::new(message.clone())
            }
        }
    }

    /// Check if two messages equal.
    ///
    /// # Panics
    ///
    /// Is any message has different type than this descriptor.
    pub fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.eq(a, b),
            MessageDescriptorImplRef::Dynamic(..) => unimplemented!(),
        }
    }

    /// Similar to `eq`, but considers `NaN` values equal.
    ///
    /// # Panics
    ///
    /// Is any message has different type than this descriptor.
    pub(crate) fn reflect_eq(
        &self,
        a: &dyn MessageDyn,
        b: &dyn MessageDyn,
        mode: &ReflectEqMode,
    ) -> bool {
        // Explicitly force panic even if field list is empty
        assert_eq!(self, &a.descriptor_dyn());
        assert_eq!(self, &b.descriptor_dyn());

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

    pub(crate) fn reflect_eq_maybe_unrelated(
        a: &dyn MessageDyn,
        b: &dyn MessageDyn,
        mode: &ReflectEqMode,
    ) -> bool {
        let ad = a.descriptor_dyn();
        let bd = b.descriptor_dyn();
        ad == bd && ad.reflect_eq(a, b, mode)
    }

    /// Fully qualified protobuf message name
    pub fn full_name(&self) -> &str {
        &self.index_entry().full_name
    }

    /// Name relative to the package where the message is declared.
    pub fn name_to_package(&self) -> &str {
        &self.index_entry().name_to_package
    }

    /// Nested oneofs including synthetic.
    pub fn all_oneofs<'a>(&'a self) -> impl Iterator<Item = OneofDescriptor> + 'a {
        self.proto()
            .oneof_decl
            .iter()
            .enumerate()
            .map(move |(index, _)| OneofDescriptor {
                message_descriptor: self.clone(),
                index,
            })
    }

    /// Non-synthetic oneofs.
    pub fn oneofs<'a>(&'a self) -> impl Iterator<Item = OneofDescriptor> + 'a {
        self.all_oneofs().filter(|oneof| !oneof.is_synthetic())
    }

    /// Message field descriptors.
    pub fn fields<'a>(&'a self) -> impl Iterator<Item = FieldDescriptor> + 'a {
        (0..self.index().fields.len()).map(move |index| FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Extension fields.
    pub fn extensions(&self) -> impl Iterator<Item = FieldDescriptor> + '_ {
        (0..self.index().extensions.len()).map(move |index| FieldDescriptor {
            imp: FieldDescriptorImpl::ExtensionInMessage(self.clone(), index),
        })
    }

    pub(crate) fn index(&self) -> &MessageIndex {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => &g.non_map().index,
            MessageDescriptorImplRef::Dynamic(d) => &d.indices,
        }
    }

    pub(crate) fn generated_index(&self) -> &'static MessageIndex {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => &g.non_map().index,
            MessageDescriptorImplRef::Dynamic(_) => panic!("dynamic message: {}", self),
        }
    }

    /// Find message field by protobuf field name
    ///
    /// Note: protobuf field name might be different for Rust field name.
    // TODO: return value, not pointer, pointer is not compatible with dynamic message
    pub fn field_by_name(&self, name: &str) -> Option<FieldDescriptor> {
        let &index = self.index().field_index_by_name.get(name)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), 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<FieldDescriptor> {
        let &index = self.index().field_index_by_name_or_json_name.get(name)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Find message field by field name
    pub fn field_by_number(&self, number: u32) -> Option<FieldDescriptor> {
        let &index = self.index().field_index_by_number.get(&number)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Parse message from stream.
    pub fn parse_from(&self, is: &mut CodedInputStream) -> crate::Result<Box<dyn MessageDyn>> {
        let mut r = self.new_instance();
        r.merge_from_dyn(is)?;
        r.check_initialized_dyn()?;
        Ok(r)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    pub fn parse_from_reader(&self, reader: &mut dyn Read) -> crate::Result<Box<dyn MessageDyn>> {
        let mut is = CodedInputStream::new(reader);
        let r = self.parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    pub fn parse_from_bytes(&self, bytes: &[u8]) -> crate::Result<Box<dyn MessageDyn>> {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = self.parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }
}

pub(crate) enum MessageDescriptorImplRef<'a> {
    Generated(&'static GeneratedMessageDescriptor),
    Dynamic(&'a DynamicMessageDescriptor),
}

#[cfg(test)]
mod test {
    use crate::descriptor::descriptor_proto::ExtensionRange;
    use crate::descriptor::DescriptorProto;
    use crate::MessageFull;

    #[test]
    #[cfg_attr(miri, ignore)] // Too slow on Miri.
    fn nested_messages() {
        assert!(DescriptorProto::descriptor_static()
            .nested_messages()
            .collect::<Vec<_>>()
            .contains(&ExtensionRange::descriptor_static()));
    }

    #[test]
    #[cfg_attr(miri, ignore)] // Too slow on Miri.
    fn enclosing_message() {
        assert_eq!(
            Some(DescriptorProto::descriptor_static()),
            ExtensionRange::descriptor_static().enclosing_message()
        );
        assert_eq!(
            None,
            DescriptorProto::descriptor_static().enclosing_message()
        );
    }
}
<commit_msg>Implement Hash for MessageDescriptor<commit_after>use std::fmt;
use std::io::Read;

use crate::descriptor::DescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::dynamic::DynamicMessage;
use crate::reflect::field::FieldDescriptorImpl;
use crate::reflect::file::index::FileIndexMessageEntry;
use crate::reflect::file::FileDescriptorImpl;
use crate::reflect::message::dynamic::DynamicMessageDescriptor;
use crate::reflect::message::generated::GeneratedMessageDescriptor;
use crate::reflect::message::index::MessageIndex;
use crate::reflect::reflect_eq::ReflectEq;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::EnumDescriptor;
use crate::reflect::FieldDescriptor;
use crate::reflect::FileDescriptor;
use crate::reflect::OneofDescriptor;
use crate::CodedInputStream;

pub(crate) mod dynamic;
pub(crate) mod generated;
pub(crate) mod index;
pub(crate) mod message_ref;
pub(crate) mod path;

/// Dynamic representation of message type.
///
/// Used for reflection.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct MessageDescriptor {
    file_descriptor: FileDescriptor,
    index: usize,
}

impl fmt::Display for MessageDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.full_name())
    }
}

impl fmt::Debug for MessageDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MessageDescriptor")
            // TODO: add smth
            .finish()
    }
}

impl MessageDescriptor {
    pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> MessageDescriptor {
        MessageDescriptor {
            file_descriptor,
            index,
        }
    }

    /// Get internal index.
    ///
    /// Only needed for codegen.
    #[doc(hidden)]
    pub fn index_in_file_for_codegen(&self) -> usize {
        self.index
    }

    /// Get underlying `DescriptorProto` object.
    pub fn proto(&self) -> &DescriptorProto {
        self.file_descriptor.message_proto(self.index)
    }

    /// Message name as specified in `.proto` file.
    pub fn name(&self) -> &str {
        self.proto().name()
    }

    /// Get enums declared in this message.
    pub fn enums(&self) -> impl Iterator<Item = EnumDescriptor> + '_ {
        let first_enum_index = self.index_entry().first_enum_index;
        self.proto()
            .enum_type
            .iter()
            .enumerate()
            .map(move |(i, _)| {
                EnumDescriptor::new(self.file_descriptor.clone(), first_enum_index + i)
            })
    }

    fn index_entry(&self) -> &FileIndexMessageEntry {
        self.file_descriptor.message_index_entry(self.index)
    }

    /// Get a message descriptor for given message type
    pub fn for_type<M: MessageFull>() -> MessageDescriptor {
        M::descriptor_static()
    }

    #[doc(hidden)]
    pub fn new_generated_2(file_descriptor: FileDescriptor, index: usize) -> MessageDescriptor {
        MessageDescriptor::new(file_descriptor, index)
    }

    /// Messages declared in this messages.
    pub fn nested_messages(&self) -> impl Iterator<Item = MessageDescriptor> + '_ {
        self.index_entry()
            .nested_messages
            .iter()
            .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), *i))
    }

    /// Get a message containing this message, or `None` if this message is declared at file level.
    pub fn enclosing_message(&self) -> Option<MessageDescriptor> {
        self.index_entry()
            .enclosing_message
            .map(|i| MessageDescriptor::new(self.file_descriptor.clone(), i))
    }

    pub(crate) fn get_impl(&self) -> MessageDescriptorImplRef {
        match &self.file_descriptor.imp {
            FileDescriptorImpl::Generated(g) => {
                MessageDescriptorImplRef::Generated(&g.messages[self.index])
            }
            FileDescriptorImpl::Dynamic(d) => {
                MessageDescriptorImplRef::Dynamic(&d.messages[self.index])
            }
        }
    }

    /// [`FileDescriptor`] containing this message.
    pub fn file_descriptor(&self) -> &FileDescriptor {
        &self.file_descriptor
    }

    /// `FileDescriptorProto` containg this message type
    pub fn file_descriptor_proto(&self) -> &FileDescriptorProto {
        self.file_descriptor().proto()
    }

    /// This message descriptor is a map entry.
    pub fn is_map_entry(&self) -> bool {
        self.proto().options.get_or_default().map_entry()
    }

    fn assert_not_map_entry(&self) {
        assert!(
            !self.is_map_entry(),
            "message is map entry: {}",
            self.full_name()
        );
    }

    /// New empty message.
    ///
    /// # Panics
    ///
    /// If this message is a map entry message.
    pub fn new_instance(&self) -> Box<dyn MessageDyn> {
        self.assert_not_map_entry();
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.new_instance(),
            MessageDescriptorImplRef::Dynamic(..) => Box::new(DynamicMessage::new(self.clone())),
        }
    }

    /// Shared immutable empty message.
    ///
    /// Returns `None` for dynamic message.
    ///
    /// # Panics
    ///
    /// If this message is a map entry message.
    pub fn default_instance(&self) -> Option<&'static dyn MessageDyn> {
        self.assert_not_map_entry();
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => Some(g.non_map().factory.default_instance()),
            MessageDescriptorImplRef::Dynamic(..) => None,
        }
    }

    /// Clone a message
    pub(crate) fn clone_message(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn> {
        assert!(&message.descriptor_dyn() == self);
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.clone(message),
            MessageDescriptorImplRef::Dynamic(..) => {
                let message: &DynamicMessage = DynamicMessage::downcast_ref(message);
                Box::new(message.clone())
            }
        }
    }

    /// Check if two messages equal.
    ///
    /// # Panics
    ///
    /// Is any message has different type than this descriptor.
    pub fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => g.non_map().factory.eq(a, b),
            MessageDescriptorImplRef::Dynamic(..) => unimplemented!(),
        }
    }

    /// Similar to `eq`, but considers `NaN` values equal.
    ///
    /// # Panics
    ///
    /// Is any message has different type than this descriptor.
    pub(crate) fn reflect_eq(
        &self,
        a: &dyn MessageDyn,
        b: &dyn MessageDyn,
        mode: &ReflectEqMode,
    ) -> bool {
        // Explicitly force panic even if field list is empty
        assert_eq!(self, &a.descriptor_dyn());
        assert_eq!(self, &b.descriptor_dyn());

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

    pub(crate) fn reflect_eq_maybe_unrelated(
        a: &dyn MessageDyn,
        b: &dyn MessageDyn,
        mode: &ReflectEqMode,
    ) -> bool {
        let ad = a.descriptor_dyn();
        let bd = b.descriptor_dyn();
        ad == bd && ad.reflect_eq(a, b, mode)
    }

    /// Fully qualified protobuf message name
    pub fn full_name(&self) -> &str {
        &self.index_entry().full_name
    }

    /// Name relative to the package where the message is declared.
    pub fn name_to_package(&self) -> &str {
        &self.index_entry().name_to_package
    }

    /// Nested oneofs including synthetic.
    pub fn all_oneofs<'a>(&'a self) -> impl Iterator<Item = OneofDescriptor> + 'a {
        self.proto()
            .oneof_decl
            .iter()
            .enumerate()
            .map(move |(index, _)| OneofDescriptor {
                message_descriptor: self.clone(),
                index,
            })
    }

    /// Non-synthetic oneofs.
    pub fn oneofs<'a>(&'a self) -> impl Iterator<Item = OneofDescriptor> + 'a {
        self.all_oneofs().filter(|oneof| !oneof.is_synthetic())
    }

    /// Message field descriptors.
    pub fn fields<'a>(&'a self) -> impl Iterator<Item = FieldDescriptor> + 'a {
        (0..self.index().fields.len()).map(move |index| FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Extension fields.
    pub fn extensions(&self) -> impl Iterator<Item = FieldDescriptor> + '_ {
        (0..self.index().extensions.len()).map(move |index| FieldDescriptor {
            imp: FieldDescriptorImpl::ExtensionInMessage(self.clone(), index),
        })
    }

    pub(crate) fn index(&self) -> &MessageIndex {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => &g.non_map().index,
            MessageDescriptorImplRef::Dynamic(d) => &d.indices,
        }
    }

    pub(crate) fn generated_index(&self) -> &'static MessageIndex {
        match self.get_impl() {
            MessageDescriptorImplRef::Generated(g) => &g.non_map().index,
            MessageDescriptorImplRef::Dynamic(_) => panic!("dynamic message: {}", self),
        }
    }

    /// Find message field by protobuf field name
    ///
    /// Note: protobuf field name might be different for Rust field name.
    // TODO: return value, not pointer, pointer is not compatible with dynamic message
    pub fn field_by_name(&self, name: &str) -> Option<FieldDescriptor> {
        let &index = self.index().field_index_by_name.get(name)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), 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<FieldDescriptor> {
        let &index = self.index().field_index_by_name_or_json_name.get(name)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Find message field by field name
    pub fn field_by_number(&self, number: u32) -> Option<FieldDescriptor> {
        let &index = self.index().field_index_by_number.get(&number)?;
        Some(FieldDescriptor {
            imp: FieldDescriptorImpl::Field(self.clone(), index),
        })
    }

    /// Parse message from stream.
    pub fn parse_from(&self, is: &mut CodedInputStream) -> crate::Result<Box<dyn MessageDyn>> {
        let mut r = self.new_instance();
        r.merge_from_dyn(is)?;
        r.check_initialized_dyn()?;
        Ok(r)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    pub fn parse_from_reader(&self, reader: &mut dyn Read) -> crate::Result<Box<dyn MessageDyn>> {
        let mut is = CodedInputStream::new(reader);
        let r = self.parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    pub fn parse_from_bytes(&self, bytes: &[u8]) -> crate::Result<Box<dyn MessageDyn>> {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = self.parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }
}

pub(crate) enum MessageDescriptorImplRef<'a> {
    Generated(&'static GeneratedMessageDescriptor),
    Dynamic(&'a DynamicMessageDescriptor),
}

#[cfg(test)]
mod test {
    use crate::descriptor::descriptor_proto::ExtensionRange;
    use crate::descriptor::DescriptorProto;
    use crate::MessageFull;

    #[test]
    #[cfg_attr(miri, ignore)] // Too slow on Miri.
    fn nested_messages() {
        assert!(DescriptorProto::descriptor_static()
            .nested_messages()
            .collect::<Vec<_>>()
            .contains(&ExtensionRange::descriptor_static()));
    }

    #[test]
    #[cfg_attr(miri, ignore)] // Too slow on Miri.
    fn enclosing_message() {
        assert_eq!(
            Some(DescriptorProto::descriptor_static()),
            ExtensionRange::descriptor_static().enclosing_message()
        );
        assert_eq!(
            None,
            DescriptorProto::descriptor_static().enclosing_message()
        );
    }
}
<|endoftext|>


<commit_before>/* BASE CONSTANTS */
pub const APPLICATION_NAME: &'static str = "rdm";

/* DBUS CONSTANTS */
pub const DBUS_SERVICE_NAME: &'static str = "com.github.1wilkens.RDM";
pub const DBUS_ROOT_PATH: &'static str = "com/github/1wilkens/RDM";

/* -- CONFIG SETTINGS -- */
pub const DEFAULT_CONFIG_FILE: &'static str = "/etc/rdm.conf";
pub const DEFAULT_RUN_DIR: &'static str = "/var/run/rdm";
pub const DEFAULT_SESSION_LOG_FILE: &'static str = "session.log";

// Change this to prevent automatic X server start e.g.
pub const TESTING: bool = false;

/* -- EXECUTABLES / DIRECTORIES -- */
pub const SH_EXECUTABLE: &'static str = "/bin/sh";
pub const X_EXECUTABLE: &'static str = "/usr/bin/X";
pub const XAUTH_EXECUTABLE: &'static str = "/usr/bin/xauth";

pub const XSESSIONS_DIRECTORY: &'static str = "/usr/share/xsessions";

/* -- X SERVER SETTINGS --*/
pub const X_DEFAULT_ARGS: [&'static str; 5] = ["-nolisten", "tcp", "-logverbose", "75", "-noreset"];
pub const X_DEFAULT_DISPLAY: &'static str = ":0";
pub const X_DEFAULT_VT: &'static str = "vt01";
pub const X_ARG_AUTH: &'static str = "-auth";
pub const X_ARG_DISPLAY_FD: &'static str = "-displayfd";
pub const X_AUTHORITY_FILE: &'static str = ".Xauthority";

/* -- THEME SETTINGS -- */
pub const THEME_BASE_PATH: &'static str = "/usr/share/rdm/themes/";

pub const THEME_MAIN_FILE_NAME: &'static str = "rdm";
pub const THEME_MAIN_FILE_EXT: &'static str = "theme";

pub const THEME_BACKGROUND_NAME: &'static str = "background";
pub const THEME_BACKGROUND_EXT: &'static str = "png";

pub const THEME_COMPONENT_WINDOW: &'static str = "window";
pub const THEME_COMPONENT_BG: &'static str = "background";
pub const THEME_COMPONENT_USER: &'static str = "user";
pub const THEME_COMPONENT_SECRET: &'static str = "secret";

pub const THEME_NAME_DEFAULT: &'static str = "default";

/* -- KEYVALS -- */
pub const KEYVAL_ENTER: u32 = 0xFF0D;
<commit_msg>[rdm] Fix clippy warnings in constants.rs<commit_after>/* BASE CONSTANTS */
pub const APPLICATION_NAME: &str = "rdm";

/* DBUS CONSTANTS */
pub const DBUS_SERVICE_NAME: &str = "com.github.1wilkens.RDM";
pub const DBUS_ROOT_PATH: &str = "com/github/1wilkens/RDM";

/* -- CONFIG SETTINGS -- */
pub const DEFAULT_CONFIG_FILE: &str = "/etc/rdm.conf";
pub const DEFAULT_RUN_DIR: &str = "/var/run/rdm";
pub const DEFAULT_SESSION_LOG_FILE: &str = "session.log";

// Change this to prevent automatic X server start e.g.
pub const TESTING: bool = false;

/* -- EXECUTABLES / DIRECTORIES -- */
pub const SH_EXECUTABLE: &str = "/bin/sh";
pub const X_EXECUTABLE: &str = "/usr/bin/X";
pub const XAUTH_EXECUTABLE: &str = "/usr/bin/xauth";

pub const XSESSIONS_DIRECTORY: &str = "/usr/share/xsessions";

/* -- X SERVER SETTINGS --*/
pub const X_DEFAULT_ARGS: [&str; 5] = ["-nolisten", "tcp", "-logverbose", "75", "-noreset"];
pub const X_DEFAULT_DISPLAY: &str = ":0";
pub const X_DEFAULT_VT: &str = "vt01";
pub const X_ARG_AUTH: &str = "-auth";
pub const X_ARG_DISPLAY_FD: &str = "-displayfd";
pub const X_AUTHORITY_FILE: &str = ".Xauthority";

/* -- THEME SETTINGS -- */
pub const THEME_BASE_PATH: &str = "/usr/share/rdm/themes/";

pub const THEME_MAIN_FILE_NAME: &str = "rdm";
pub const THEME_MAIN_FILE_EXT: &str = "theme";

pub const THEME_BACKGROUND_NAME: &str = "background";
pub const THEME_BACKGROUND_EXT: &str = "png";

pub const THEME_COMPONENT_WINDOW: &str = "window";
pub const THEME_COMPONENT_BG: &str = "background";
pub const THEME_COMPONENT_USER: &str = "user";
pub const THEME_COMPONENT_SECRET: &str = "secret";

pub const THEME_NAME_DEFAULT: &str = "default";

/* -- KEYVALS -- */
pub const KEYVAL_ENTER: u32 = 0xFF0D;
<|endoftext|>


<commit_before>
extern crate kafka;

use flowgger::Output;
use flowgger::config::Config;
use self::kafka::client::KafkaClient;
use self::kafka::utils::ProduceMessage;
use std::process::exit;
use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex};
use std::thread;

const KAFKA_DEFAULT_COALESCE: usize = 1;
const KAFKA_DEFAULT_THREADS: u32 = 1;
const KAFKA_DEFAULT_TIMEOUT: i32 = 60;
const KAFKA_DEFAULT_ACKS: i16 = 0;

pub struct KafkaPool {
    config: KafkaConfig,
    threads: u32
}

#[derive(Clone)]
struct KafkaConfig {
    acks: i16,
    brokers: Vec<String>,
    topic: String,
    timeout: i32,
    coalesce: usize
}

struct KafkaWorker {
    arx: Arc<Mutex<Receiver<Vec<u8>>>>,
    client: KafkaClient,
    config: KafkaConfig,
    queue: Vec<ProduceMessage>
}

impl KafkaWorker {
    fn new(arx: Arc<Mutex<Receiver<Vec<u8>>>>, config: KafkaConfig) -> KafkaWorker {
        let mut client = KafkaClient::new(config.brokers.clone());
        match client.load_metadata_all() {
            Ok(_) => {},
            Err(e) => {
                println!("Unable to connect to Kafka: [{}]", e);
                exit(1);
            }
        }
        let queue = Vec::with_capacity(config.coalesce);
        KafkaWorker {
            arx: arx,
            client: client,
            config: config,
            queue: queue
        }
    }

    fn run_nocoalesce(&mut self) {
        loop {
            let bytes = match { self.arx.lock().unwrap().recv() } {
                Ok(line) => line,
                Err(_) => return
            };
            match self.client.send_message(self.config.acks, self.config.timeout, self.config.topic.clone(), bytes) {
                Ok(_) => {},
                Err(e) => {
                    println!("Kafka not responsive: [{}]", e);
                    exit(1);
                }
            }
        }
    }

    fn run_coalesce(&mut self) {
        loop {
            let bytes = match { self.arx.lock().unwrap().recv() } {
                Ok(line) => line,
                Err(_) => return
            };
            let message = ProduceMessage {
                topic: self.config.topic.clone(),
                message: bytes
            };
            let ref mut queue = self.queue;
            queue.push(message);
            if queue.len() >= self.config.coalesce {
                match self.client.send_messages(self.config.acks, self.config.timeout, queue.clone()) {
                    Ok(_) => {},
                    Err(e) => {
                        println!("Kafka not responsive: [{}]", e);
                        exit(1);
                    }
                }
                queue.clear();
            }
        }
    }

    fn run(&mut self) {
        if self.config.coalesce <= 1 {
            self.run_nocoalesce()
        } else {
            self.run_coalesce()
        }
    }
}

impl Output for KafkaPool {
    fn new(config: &Config) -> KafkaPool {
        let acks = config.lookup("output.kafka_acks").
            map_or(KAFKA_DEFAULT_ACKS, |x| x.as_integer().unwrap() as i16);
        let brokers = config.lookup("output.kafka_brokers").unwrap().as_slice().unwrap().to_vec();
        let brokers = brokers.iter().map(|x| x.as_str().unwrap().to_owned()).collect();
        let topic = config.lookup("output.kafka_topic").unwrap().as_str().unwrap().to_owned();
        let timeout = config.lookup("output.kafka_timeout").
            map_or(KAFKA_DEFAULT_TIMEOUT, |x| x.as_integer().unwrap() as i32);
        let threads = config.lookup("output.kafka_threads").
            map_or(KAFKA_DEFAULT_THREADS, |x| x.as_integer().unwrap() as u32);
        let coalesce = config.lookup("output.kafka_coalesce").
            map_or(KAFKA_DEFAULT_COALESCE, |x| x.as_integer().unwrap() as usize);
        let kafka_config = KafkaConfig {
            acks: acks,
            brokers: brokers,
            topic: topic,
            timeout: timeout,
            coalesce: coalesce
        };
        KafkaPool {
            config: kafka_config,
            threads: threads
        }
    }

    fn start(&self, arx: Arc<Mutex<Receiver<Vec<u8>>>>) {
        for i in 0..self.threads {
            let arx = arx.clone();
            let config = self.config.clone();
            thread::spawn(move || {
                let mut worker = KafkaWorker::new(arx, config);
                worker.run();
            });
        }
    }
}
<commit_msg>Increase the default Kafka timeout<commit_after>
extern crate kafka;

use flowgger::Output;
use flowgger::config::Config;
use self::kafka::client::KafkaClient;
use self::kafka::utils::ProduceMessage;
use std::process::exit;
use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex};
use std::thread;

const KAFKA_DEFAULT_COALESCE: usize = 1;
const KAFKA_DEFAULT_THREADS: u32 = 1;
const KAFKA_DEFAULT_TIMEOUT: i32 = 60000;
const KAFKA_DEFAULT_ACKS: i16 = 0;

pub struct KafkaPool {
    config: KafkaConfig,
    threads: u32
}

#[derive(Clone)]
struct KafkaConfig {
    acks: i16,
    brokers: Vec<String>,
    topic: String,
    timeout: i32,
    coalesce: usize
}

struct KafkaWorker {
    arx: Arc<Mutex<Receiver<Vec<u8>>>>,
    client: KafkaClient,
    config: KafkaConfig,
    queue: Vec<ProduceMessage>
}

impl KafkaWorker {
    fn new(arx: Arc<Mutex<Receiver<Vec<u8>>>>, config: KafkaConfig) -> KafkaWorker {
        let mut client = KafkaClient::new(config.brokers.clone());
        match client.load_metadata_all() {
            Ok(_) => {},
            Err(e) => {
                println!("Unable to connect to Kafka: [{}]", e);
                exit(1);
            }
        }
        let queue = Vec::with_capacity(config.coalesce);
        KafkaWorker {
            arx: arx,
            client: client,
            config: config,
            queue: queue
        }
    }

    fn run_nocoalesce(&mut self) {
        loop {
            let bytes = match { self.arx.lock().unwrap().recv() } {
                Ok(line) => line,
                Err(_) => return
            };
            match self.client.send_message(self.config.acks, self.config.timeout, self.config.topic.clone(), bytes) {
                Ok(_) => {},
                Err(e) => {
                    println!("Kafka not responsive: [{}]", e);
                    exit(1);
                }
            }
        }
    }

    fn run_coalesce(&mut self) {
        loop {
            let bytes = match { self.arx.lock().unwrap().recv() } {
                Ok(line) => line,
                Err(_) => return
            };
            let message = ProduceMessage {
                topic: self.config.topic.clone(),
                message: bytes
            };
            let ref mut queue = self.queue;
            queue.push(message);
            if queue.len() >= self.config.coalesce {
                match self.client.send_messages(self.config.acks, self.config.timeout, queue.clone()) {
                    Ok(_) => {},
                    Err(e) => {
                        println!("Kafka not responsive: [{}]", e);
                        exit(1);
                    }
                }
                queue.clear();
            }
        }
    }

    fn run(&mut self) {
        if self.config.coalesce <= 1 {
            self.run_nocoalesce()
        } else {
            self.run_coalesce()
        }
    }
}

impl Output for KafkaPool {
    fn new(config: &Config) -> KafkaPool {
        let acks = config.lookup("output.kafka_acks").
            map_or(KAFKA_DEFAULT_ACKS, |x| x.as_integer().unwrap() as i16);
        let brokers = config.lookup("output.kafka_brokers").unwrap().as_slice().unwrap().to_vec();
        let brokers = brokers.iter().map(|x| x.as_str().unwrap().to_owned()).collect();
        let topic = config.lookup("output.kafka_topic").unwrap().as_str().unwrap().to_owned();
        let timeout = config.lookup("output.kafka_timeout").
            map_or(KAFKA_DEFAULT_TIMEOUT, |x| x.as_integer().unwrap() as i32);
        let threads = config.lookup("output.kafka_threads").
            map_or(KAFKA_DEFAULT_THREADS, |x| x.as_integer().unwrap() as u32);
        let coalesce = config.lookup("output.kafka_coalesce").
            map_or(KAFKA_DEFAULT_COALESCE, |x| x.as_integer().unwrap() as usize);
        let kafka_config = KafkaConfig {
            acks: acks,
            brokers: brokers,
            topic: topic,
            timeout: timeout,
            coalesce: coalesce
        };
        KafkaPool {
            config: kafka_config,
            threads: threads
        }
    }

    fn start(&self, arx: Arc<Mutex<Receiver<Vec<u8>>>>) {
        for i in 0..self.threads {
            let arx = arx.clone();
            let config = self.config.clone();
            thread::spawn(move || {
                let mut worker = KafkaWorker::new(arx, config);
                worker.run();
            });
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use futures::task::Task;
use futures::task;

use futures::Async;
use futures::Poll;
use futures::stream::Stream;

enum State {
    Open = 0,
    Closed = 1,
    ControllerDead = 2,
}

const OPEN: usize = State::Open as usize;
const CLOSED: usize = State::Closed as usize;
const CONTROLLER_DEAD: usize = State::ControllerDead as usize;

impl State {
    fn from(value: usize) -> State {
        match value {
            OPEN => State::Open,
            CLOSED => State::Closed,
            CONTROLLER_DEAD => State::ControllerDead,
            _ => unreachable!(),
        }
    }
}

struct Guarded {
    task: Option<Task>,
}

struct Shared {
    state: AtomicUsize,
    guarded: Mutex<Guarded>,
}

pub struct LatchController {
    shared: Arc<Shared>,
}

pub struct Latch {
    shared: Arc<Shared>,
}

pub fn latch() -> (LatchController, Latch) {
    let shared = Arc::new(Shared {
        state: AtomicUsize::new(CLOSED),
        guarded: Mutex::new(Guarded {
            task: None,
        }),
    });
    (LatchController { shared: shared.clone() }, Latch { shared: shared })
}

impl LatchController {
    pub fn open(&self) {
        if self.shared.state.load(Ordering::SeqCst) == OPEN as usize {
            return;
        }

        self.shared.state.store(OPEN, Ordering::SeqCst);

        let mut guard = self.shared.guarded.lock().expect("lock");
        if let Some(task) = guard.task.take() {
            task.notify();
        }
    }

    pub fn close(&self) {
        if self.shared.state.load(Ordering::SeqCst) == CLOSED as usize {
            return;
        }

        self.shared.state.store(CLOSED, Ordering::SeqCst);

        // no need to unpark, because nobody is subscribed to close
    }
}

impl Drop for LatchController {
    fn drop(&mut self) {
        self.shared.state.store(CONTROLLER_DEAD, Ordering::SeqCst);

        let mut guard = self.shared.guarded.lock().expect("lock");
        if let Some(task) = guard.task.take() {
            task.notify();
        }
    }
}

impl Stream for Latch {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let state = self.shared.state.load(Ordering::SeqCst);
        let state = State::from(state);

        match state {
            State::Open => Ok(Async::Ready(Some(()))),
            State::ControllerDead => Err(()),
            State::Closed => {
                let mut guard = self.shared.guarded.lock().expect("lock");
                guard.task = Some(task::current());
                Ok(Async::NotReady)
            }
        }
    }
}

#[cfg(test)]
mod test {

    use std::fmt::Debug;

    use futures::executor::NotifyHandle;
    use futures::executor::Notify;
    use futures::executor::Spawn;
    use futures::executor;
    use futures::Poll;

    use super::*;

    fn notify_noop() -> NotifyHandle {
        struct Noop;

        impl Notify for Noop {
            fn notify(&self, _id: usize) {}
        }

        const NOOP : &'static Noop = &Noop;

        NotifyHandle::from(NOOP)
    }

    fn assert_notify_stream<S>(
        expected: Poll<Option<S::Item>, S::Error>,
        stream: &mut Spawn<S>)
        where
            S : Stream,
            S::Item : Debug,
            S::Item : PartialEq,
            S::Error : Debug,
            S::Error : PartialEq,
    {
        assert_eq!(
            expected,
            stream.poll_stream_notify(&notify_noop(), 1));
    }

    #[test]
    fn test() {
        let (c, l) = latch();

        let mut l = executor::spawn(l);

        // initially closed
        assert_notify_stream(Ok(Async::NotReady), &mut l);
        assert_notify_stream(Ok(Async::NotReady), &mut l);

        c.open();

        assert_notify_stream(Ok(Async::Ready(Some(()))), &mut l);
        assert_notify_stream(Ok(Async::Ready(Some(()))), &mut l);

        c.close();

        assert_notify_stream(Ok(Async::NotReady), &mut l);

        c.close();

        assert_notify_stream(Ok(Async::NotReady), &mut l);
    }

}
<commit_msg>Rewrite latch using AtomicIntOrBox<commit_after>use std::sync::Arc;

use futures::task::Task;
use futures::task;

use futures::Async;
use futures::Poll;
use futures::stream::Stream;

use super::atomic_int_box::*;

enum State {
    Open = 0,
    Closed = 1,
    ControllerDead = 2,
}

const OPEN: u32 = State::Open as u32;
const CLOSED: u32 = State::Closed as u32;
const CONTROLLER_DEAD: u32 = State::ControllerDead as u32;

struct Shared {
    state: AtomicIntOrBox<Task>,
}

pub struct LatchController {
    shared: Arc<Shared>,
}

pub struct Latch {
    shared: Arc<Shared>,
}

pub fn latch() -> (LatchController, Latch) {
    let shared = Arc::new(Shared {
        state: AtomicIntOrBox::from_int(CLOSED),
    });
    (LatchController { shared: shared.clone() }, Latch { shared: shared })
}

impl LatchController {
    pub fn open(&self) {
        // fast track
        if let DecodedRef::Int(OPEN) = self.shared.state.load() {
            return;
        }

        if let DecodedBox::Box(task) = self.shared.state.swap(DecodedBox::Int(OPEN)) {
            task.notify();
        }
    }

    pub fn close(&self) {
        // fast track
        if let DecodedRef::Int(CLOSED) = self.shared.state.load() {
            return;
        }

        self.shared.state.store(DecodedBox::Int(CLOSED));

        // no need to unpark, because nobody is subscribed to close
    }
}

impl Drop for LatchController {
    fn drop(&mut self) {
        if let DecodedBox::Box(task) = self.shared.state.swap(DecodedBox::Int(CONTROLLER_DEAD)) {
            task.notify();
        }
    }
}

impl Stream for Latch {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let s = match self.shared.state.load() {
                DecodedRef::Int(OPEN) => return Ok(Async::Ready(Some(()))),
                DecodedRef::Int(CONTROLLER_DEAD) => return Err(()),
                s => s,
            };

            match self.shared.state.compare_exchange(s, DecodedBox::Box(Box::new(task::current()))) {
                Ok(_) => return Ok(Async::NotReady),
                _ => {}
            }
        }
    }
}

#[cfg(test)]
mod test {

    use std::fmt::Debug;

    use futures::executor::NotifyHandle;
    use futures::executor::Notify;
    use futures::executor::Spawn;
    use futures::executor;
    use futures::Poll;

    use super::*;

    fn notify_noop() -> NotifyHandle {
        struct Noop;

        impl Notify for Noop {
            fn notify(&self, _id: usize) {}
        }

        const NOOP : &'static Noop = &Noop;

        NotifyHandle::from(NOOP)
    }

    fn assert_notify_stream<S>(
        expected: Poll<Option<S::Item>, S::Error>,
        stream: &mut Spawn<S>)
        where
            S : Stream,
            S::Item : Debug,
            S::Item : PartialEq,
            S::Error : Debug,
            S::Error : PartialEq,
    {
        assert_eq!(
            expected,
            stream.poll_stream_notify(&notify_noop(), 1));
    }

    #[test]
    fn test() {
        let (c, l) = latch();

        let mut l = executor::spawn(l);

        // initially closed
        assert_notify_stream(Ok(Async::NotReady), &mut l);
        assert_notify_stream(Ok(Async::NotReady), &mut l);

        c.open();

        assert_notify_stream(Ok(Async::Ready(Some(()))), &mut l);
        assert_notify_stream(Ok(Async::Ready(Some(()))), &mut l);

        c.close();

        assert_notify_stream(Ok(Async::NotReady), &mut l);

        c.close();

        assert_notify_stream(Ok(Async::NotReady), &mut l);
    }

}
<|endoftext|>


<commit_before>use clap::{App, ArgMatches};

use prelude::*;
use config::Config;
use utils::ArgExt;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("uploads react-native projects from within a gradle build step")
        .org_project_args()
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    Ok(())
}
<commit_msg>Disable gradle command for now<commit_after>use clap::{App, ArgMatches, AppSettings};

use prelude::*;
use config::Config;
use utils::ArgExt;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("uploads react-native projects from within a gradle build step")
        .setting(AppSettings::Hidden)
        .org_project_args()
}

pub fn execute<'a>(_matches: &ArgMatches<'a>, _config: &Config) -> Result<()> {
    Err(Error::from("this command is currently not implemented"))
}
<|endoftext|>


<commit_before>//! Methods to construct generic streaming and blocking unary operators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::nested::subgraph::Source::ScopeOutput;
use progress::nested::subgraph::Target::ScopeInput;

use progress::count_map::CountMap;
use progress::notificator::Notificator;
use progress::{Timestamp, Scope, Antichain};
use communication::observer::Tee;
use communication::observer::Counter as ObserverCounter;
use communication::observer::buffer::Buffer as ObserverBuffer;
use communication::pact::ParallelizationContract;
use communication::pullable::Counter as PullableCounter;
use communication::{Data, Pullable};

use construction::{Stream, GraphBuilder};

use drain::DrainExt;

type Input<T, D, P> = PullableCounter<T, D, P>;
type Output<T, D> = ObserverBuffer<ObserverCounter<Tee<T, D>>>;

/// Methods to construct generic streaming and blocking unary operators.

pub trait Unary<G: GraphBuilder, D1: Data> {
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream and
    /// write to the output stream.
    ///
    /// #Examples
    /// ```
    /// use communication::pact::Pipeline;
    /// source.unary_stream(Pipeline, "example", |input, output| {
    ///     while let Some((time, data)) = input.pul() {
    ///         output.session(time).give_message(data);
    ///     }
    /// });
    /// ```
    fn unary_stream<D2: Data,
             L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                      &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (&self, pact: P, name: &str, logic: L) -> Stream<G, D2>;
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream,
    /// write to the output stream, and request and receive notifications. The method also requires
    /// a vector of initial notifications the operator requires (commonly none).
    ///
    /// #Examples
    /// ```
    /// use communication::pact::Pipeline;
    /// source.unary_notify(Pipeline, "example", vec![], |input, output, notificator| {
    ///     while let Some((time, data)) = input.pul() {
    ///         output.session(time).give_message(data);
    ///     }
    /// }
    /// ```
    fn unary_notify<D2: Data,
            L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                     &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2>;

}

impl<G: GraphBuilder, D1: Data> Unary<G, D1> for Stream<G, D1> {
    fn unary_notify<D2: Data,
            L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                     &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2> {

        let mut builder = self.builder();   // clones the builder

        let (sender, receiver) = pact.connect(&mut builder);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets, name.to_owned(), logic, Some((init, builder.peers())));
        let index = builder.add_scope(scope);

        self.connect_to(ScopeInput(index, 0), sender);

        Stream::new(ScopeOutput(index, 0), registrar, builder)
    }

    fn unary_stream<D2: Data,
             L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                      &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, mut logic: L) -> Stream<G, D2> {

        let mut builder = self.builder();

        let (sender, receiver) = pact.connect(&mut builder);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets, name.to_owned(), move |i,o,_| logic(i,o), None);
        let index = builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);

        Stream::new(ScopeOutput(index, 0), registrar, builder)
    }
}

struct UnaryScopeHandle<T: Timestamp, D1: Data, D2: Data, P: Pullable<T, D1>> {
    pub input:          PullableCounter<T, D1, P>,
    pub output:         ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
    pub notificator:    Notificator<T>,
}

struct UnaryScope
    <
    T: Timestamp,
    D1: Data,
    D2: Data,
    P: Pullable<T, D1>,
    L: FnMut(&mut PullableCounter<T, D1, P>,
             &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
             &mut Notificator<T>)> {
    name:           String,
    handle:         UnaryScopeHandle<T, D1, D2, P>,
    logic:          L,
    notify:         Option<(Vec<T>, u64)>,    // initial notifications and peers
}

impl<T:  Timestamp,
     D1: Data,
     D2: Data,
     P:  Pullable<T, D1>,
     L:  FnMut(&mut PullableCounter<T, D1, P>,
               &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
               &mut Notificator<T>)>
UnaryScope<T, D1, D2, P, L> {
    pub fn new(receiver: P,
               targets:  Tee<T, D2>,
               name:     String,
               logic:    L,
               notify:   Option<(Vec<T>, u64)>)
           -> UnaryScope<T, D1, D2, P, L> {
        UnaryScope {
            name:    name,
            handle:  UnaryScopeHandle {
                input:       PullableCounter::new(receiver),
                output:      ObserverBuffer::new(ObserverCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
                notificator: Default::default(),
            },
            logic:   logic,
            notify:  notify,
        }
    }
}

impl<T, D1, D2, P, L> Scope<T> for UnaryScope<T, D1, D2, P, L>
where T: Timestamp,
      D1: Data, D2: Data,
      P: Pullable<T, D1>,
      L: FnMut(&mut PullableCounter<T, D1, P>,
               &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
               &mut Notificator<T>) {
    fn inputs(&self) -> u64 { 1 }
    fn outputs(&self) -> u64 { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut internal = vec![CountMap::new()];
        if let Some((ref mut initial, peers)) = self.notify {
            for time in initial.drain_temp() {
                for _ in (0..peers) {
                    self.handle.notificator.notify_at(&time);
                }
            }

            self.handle.notificator.pull_progress(&mut internal[0]);
        }
        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>,
                                       frontier: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>],
                                         consumed: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        (self.logic)(&mut self.handle.input, &mut self.handle.output, &mut self.handle.notificator);

        self.handle.output.flush_and_shut();

        // extract what we know about progress from the input and output adapters.
        self.handle.input.pull_progress(&mut consumed[0]);
        self.handle.output.inner().pull_progress(&mut produced[0]);
        self.handle.notificator.pull_progress(&mut internal[0]);

        return false;   // no unannounced internal work
    }

    fn name(&self) -> String { format!("{}", self.name) }
    fn notify_me(&self) -> bool { self.notify.is_some() }
}
<commit_msg>documentation<commit_after>//! Methods to construct generic streaming and blocking unary operators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::nested::subgraph::Source::ScopeOutput;
use progress::nested::subgraph::Target::ScopeInput;

use progress::count_map::CountMap;
use progress::notificator::Notificator;
use progress::{Timestamp, Scope, Antichain};
use communication::observer::Tee;
use communication::observer::Counter as ObserverCounter;
use communication::observer::buffer::Buffer as ObserverBuffer;
use communication::pact::ParallelizationContract;
use communication::pullable::Counter as PullableCounter;
use communication::{Data, Pullable};

use construction::{Stream, GraphBuilder};

use drain::DrainExt;

type Input<T, D, P> = PullableCounter<T, D, P>;
type Output<T, D> = ObserverBuffer<ObserverCounter<Tee<T, D>>>;

/// Methods to construct generic streaming and blocking unary operators.

pub trait Unary<G: GraphBuilder, D1: Data> {
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream and
    /// write to the output stream.
    ///
    /// #Examples
    /// ```ignore
    /// use communication::pact::Pipeline;
    /// source.unary_stream(Pipeline, "example", |input, output| {
    ///     while let Some((time, data)) = input.pull() {
    ///         output.session(time).give_message(data);
    ///     }
    /// });
    /// ```
    fn unary_stream<
        D2: Data,
        L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                 &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>)+'static,
        P: ParallelizationContract<G::Timestamp, D1>>
            (&self, pact: P, name: &str, logic: L) -> Stream<G, D2>;
    /// Creates a new dataflow operator that partitions its input stream by a parallelization
    /// strategy `pact`, and repeatedly invokes `logic` which can read from the input stream,
    /// write to the output stream, and request and receive notifications. The method also requires
    /// a vector of initial notifications the operator requires (commonly none).
    ///
    /// #Examples
    /// ```ignore
    /// use communication::pact::Pipeline;
    /// source.unary_notify(Pipeline, "example", vec![], |input, output, notificator| {
    ///     while let Some((time, data)) = input.pull() {
    ///         output.session(time).give_message(data);
    ///     }
    /// }
    /// ```
    fn unary_notify<D2: Data,
            L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                     &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2>;

}

impl<G: GraphBuilder, D1: Data> Unary<G, D1> for Stream<G, D1> {
    fn unary_notify<D2: Data,
            L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                     &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>,
                     &mut Notificator<G::Timestamp>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, init: Vec<G::Timestamp>, logic: L) -> Stream<G, D2> {

        let mut builder = self.builder();   // clones the builder

        let (sender, receiver) = pact.connect(&mut builder);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets, name.to_owned(), logic, Some((init, builder.peers())));
        let index = builder.add_scope(scope);

        self.connect_to(ScopeInput(index, 0), sender);

        Stream::new(ScopeOutput(index, 0), registrar, builder)
    }

    fn unary_stream<D2: Data,
             L: FnMut(&mut PullableCounter<G::Timestamp, D1, P::Pullable>,
                      &mut ObserverBuffer<ObserverCounter<Tee<G::Timestamp, D2>>>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (&self, pact: P, name: &str, mut logic: L) -> Stream<G, D2> {

        let mut builder = self.builder();

        let (sender, receiver) = pact.connect(&mut builder);
        let (targets, registrar) = Tee::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets, name.to_owned(), move |i,o,_| logic(i,o), None);
        let index = builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);

        Stream::new(ScopeOutput(index, 0), registrar, builder)
    }
}

struct UnaryScopeHandle<T: Timestamp, D1: Data, D2: Data, P: Pullable<T, D1>> {
    pub input:          PullableCounter<T, D1, P>,
    pub output:         ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
    pub notificator:    Notificator<T>,
}

struct UnaryScope
    <
    T: Timestamp,
    D1: Data,
    D2: Data,
    P: Pullable<T, D1>,
    L: FnMut(&mut PullableCounter<T, D1, P>,
             &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
             &mut Notificator<T>)> {
    name:           String,
    handle:         UnaryScopeHandle<T, D1, D2, P>,
    logic:          L,
    notify:         Option<(Vec<T>, u64)>,    // initial notifications and peers
}

impl<T:  Timestamp,
     D1: Data,
     D2: Data,
     P:  Pullable<T, D1>,
     L:  FnMut(&mut PullableCounter<T, D1, P>,
               &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
               &mut Notificator<T>)>
UnaryScope<T, D1, D2, P, L> {
    pub fn new(receiver: P,
               targets:  Tee<T, D2>,
               name:     String,
               logic:    L,
               notify:   Option<(Vec<T>, u64)>)
           -> UnaryScope<T, D1, D2, P, L> {
        UnaryScope {
            name:    name,
            handle:  UnaryScopeHandle {
                input:       PullableCounter::new(receiver),
                output:      ObserverBuffer::new(ObserverCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
                notificator: Default::default(),
            },
            logic:   logic,
            notify:  notify,
        }
    }
}

impl<T, D1, D2, P, L> Scope<T> for UnaryScope<T, D1, D2, P, L>
where T: Timestamp,
      D1: Data, D2: Data,
      P: Pullable<T, D1>,
      L: FnMut(&mut PullableCounter<T, D1, P>,
               &mut ObserverBuffer<ObserverCounter<Tee<T, D2>>>,
               &mut Notificator<T>) {
    fn inputs(&self) -> u64 { 1 }
    fn outputs(&self) -> u64 { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut internal = vec![CountMap::new()];
        if let Some((ref mut initial, peers)) = self.notify {
            for time in initial.drain_temp() {
                for _ in (0..peers) {
                    self.handle.notificator.notify_at(&time);
                }
            }

            self.handle.notificator.pull_progress(&mut internal[0]);
        }
        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>,
                                       frontier: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>],
                                         consumed: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        (self.logic)(&mut self.handle.input, &mut self.handle.output, &mut self.handle.notificator);

        self.handle.output.flush_and_shut();

        // extract what we know about progress from the input and output adapters.
        self.handle.input.pull_progress(&mut consumed[0]);
        self.handle.output.inner().pull_progress(&mut produced[0]);
        self.handle.notificator.pull_progress(&mut internal[0]);

        return false;   // no unannounced internal work
    }

    fn name(&self) -> String { format!("{}", self.name) }
    fn notify_me(&self) -> bool { self.notify.is_some() }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),

    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),

    /// Used only for *fat pointers* with layout::abi::ScalarPair
    ///
    /// Needed for pattern matching code related to slices and strings.
    ScalarPair(Scalar, Scalar),

    /// An allocation + offset into the allocation.
    /// Invariant: The AllocId matches the allocation.
    ByRef(AllocId, &'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    #[inline]
    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        })
    }

    #[inline]
    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar<Tag=(), Id=AllocId> {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer<Tag, Id>),
}

impl<'tcx> Scalar<()> {
    #[inline]
    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
        where Tag: Default
    {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }
}

impl<'tcx, Tag> Scalar<Tag> {
    #[inline]
    pub fn erase_tag(self) -> Scalar {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }

    #[inline]
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    #[inline]
    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    #[inline]
    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    #[inline]
    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } =>  {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    #[inline]
    pub fn is_null(self) -> bool {
        match self {
            Scalar::Bits { bits, .. } => bits == 0,
            Scalar::Ptr(_) => false
        }
    }

    #[inline]
    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    #[inline]
    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    #[inline]
    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
        let i = i.into();
        debug_assert_eq!(truncate(i, size), i,
                         "Unsigned value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: i, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
                         "Signed value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_f32(f: f32) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
    }

    #[inline]
    pub fn from_f64(f: f64) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    #[inline]
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
        match self {
            Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
            Scalar::Bits { .. } => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    #[inline]
    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    #[inline]
    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }

    pub fn to_char(self) -> EvalResult<'tcx, char> {
        let val = self.to_u32()?;
        match ::std::char::from_u32(val) {
            Some(c) => Ok(c),
            None => err!(InvalidChar(val as u128)),
        }
    }

    pub fn to_u8(self) -> EvalResult<'static, u8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u8 as u128, b);
        Ok(b as u8)
    }

    pub fn to_u32(self) -> EvalResult<'static, u32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u32 as u128, b);
        Ok(b as u32)
    }

    pub fn to_u64(self) -> EvalResult<'static, u64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_i8(self) -> EvalResult<'static, i8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i8 as i128, b);
        Ok(b as i8)
    }

    pub fn to_i32(self) -> EvalResult<'static, i32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i32 as i128, b);
        Ok(b as i32)
    }

    pub fn to_i64(self) -> EvalResult<'static, i64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    #[inline]
    pub fn to_f32(self) -> EvalResult<'static, f32> {
        Ok(f32::from_bits(self.to_u32()?))
    }

    #[inline]
    pub fn to_f64(self) -> EvalResult<'static, f64> {
        Ok(f64::from_bits(self.to_u64()?))
    }
}

impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        Scalar::Ptr(ptr)
    }
}
<commit_msg>Remove is_null<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),

    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),

    /// Used only for *fat pointers* with layout::abi::ScalarPair
    ///
    /// Needed for pattern matching code related to slices and strings.
    ScalarPair(Scalar, Scalar),

    /// An allocation + offset into the allocation.
    /// Invariant: The AllocId matches the allocation.
    ByRef(AllocId, &'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    #[inline]
    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        })
    }

    #[inline]
    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar<Tag=(), Id=AllocId> {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer<Tag, Id>),
}

impl<'tcx> Scalar<()> {
    #[inline]
    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
        where Tag: Default
    {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }
}

impl<'tcx, Tag> Scalar<Tag> {
    #[inline]
    pub fn erase_tag(self) -> Scalar {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }

    #[inline]
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    #[inline]
    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    #[inline]
    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    #[inline]
    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    #[inline]
    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    #[inline]
    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    #[inline]
    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
        let i = i.into();
        debug_assert_eq!(truncate(i, size), i,
                         "Unsigned value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: i, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
                         "Signed value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_f32(f: f32) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
    }

    #[inline]
    pub fn from_f64(f: f64) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    #[inline]
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
        match self {
            Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
            Scalar::Bits { .. } => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    #[inline]
    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    #[inline]
    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }

    pub fn to_char(self) -> EvalResult<'tcx, char> {
        let val = self.to_u32()?;
        match ::std::char::from_u32(val) {
            Some(c) => Ok(c),
            None => err!(InvalidChar(val as u128)),
        }
    }

    pub fn to_u8(self) -> EvalResult<'static, u8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u8 as u128, b);
        Ok(b as u8)
    }

    pub fn to_u32(self) -> EvalResult<'static, u32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u32 as u128, b);
        Ok(b as u32)
    }

    pub fn to_u64(self) -> EvalResult<'static, u64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_i8(self) -> EvalResult<'static, i8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i8 as i128, b);
        Ok(b as i8)
    }

    pub fn to_i32(self) -> EvalResult<'static, i32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i32 as i128, b);
        Ok(b as i32)
    }

    pub fn to_i64(self) -> EvalResult<'static, i64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    #[inline]
    pub fn to_f32(self) -> EvalResult<'static, f32> {
        Ok(f32::from_bits(self.to_u32()?))
    }

    #[inline]
    pub fn to_f64(self) -> EvalResult<'static, f64> {
        Ok(f64::from_bits(self.to_u64()?))
    }
}

impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        Scalar::Ptr(ptr)
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    fn f(dungeon: &Vec<Vec<i32>>, row: i32, col: i32, memo: &mut Vec<Vec<i32>>) -> i32 {
        let max_rows = dungeon.len() as i32;
        let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
        if row == max_rows || col == max_cols {
            return i32::MAX;
        }
        if memo[row as usize][col as usize] != -1 {
            return memo[row as usize][col as usize];
        }
        let value = &dungeon[row as usize][col as usize];
        if row == max_rows - 1 && col == max_cols - 1 {
            return if *value <= 0 { -value + 1 } else { 1 };
        }
        let right = f(dungeon, row, col + 1, memo);
        let down = f(dungeon, row + 1, col, memo);
        let min = right.min(down) - value;
        let min = if min <= 0 { 1 } else { min };
        memo[row as usize][col as usize] = min;
        min
    }

    let max_rows = dungeon.len() as i32;
    let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
    f(
        &dungeon,
        0,
        0,
        &mut vec![vec![-1; max_cols as usize]; max_rows as usize],
    )
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![5, 10, 1], vec![10, 30, 5]])
    ); // 1
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 3
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![-5, -10, 1], vec![10, 30, 5]])
    ); // 1
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<commit_msg>Update problem 174<commit_after>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    fn f(dungeon: &Vec<Vec<i32>>, row: i32, col: i32, memo: &mut Vec<Vec<i32>>) -> i32 {
        let max_row = dungeon.len() as i32;
        let max_col = if max_row > 0 { dungeon[0].len() } else { 0 } as i32;
        if row == max_row || col == max_col {
            return i32::MAX;
        }
        if memo[row as usize][col as usize] != -1 {
            return memo[row as usize][col as usize];
        }
        let value = &dungeon[row as usize][col as usize];
        if row == max_row - 1 && col == max_col - 1 {
            return if *value <= 0 { -value + 1 } else { 1 };
        }
        let right = f(dungeon, row, col + 1, memo);
        let down = f(dungeon, row + 1, col, memo);
        let min = right.min(down) - value;
        let min = if min <= 0 { 1 } else { min };
        memo[row as usize][col as usize] = min;
        min
    }

    let max_rows = dungeon.len() as i32;
    let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
    f(
        &dungeon,
        0,
        0,
        &mut vec![vec![-1; max_cols as usize]; max_rows as usize],
    )
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![5, 10, 1], vec![10, 30, 5]])
    ); // 1
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 3
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![-5, -10, 1], vec![10, 30, 5]])
    ); // 1
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<|endoftext|>


<commit_before>use fs::fields as f;
use output::colours::Colours;
use output::cell::{TextCell, DisplayWidth};
use ansi_term::{ANSIString, Style};

impl f::PermissionsPlus {
    pub fn render(&self, colours: &Colours) -> TextCell {
        let x_colour = if self.file_type.is_regular_file() { colours.perms.user_execute_file }
                                                      else { colours.perms.user_execute_other };

        let mut chars = vec![ self.file_type.render(colours) ];
        chars.extend(self.permissions.render(colours, x_colour));

        if self.xattrs {
           chars.push(colours.perms.attribute.paint("@"));
        }

        // As these are all ASCII characters, we can guarantee that they’re
        // all going to be one character wide, and don’t need to compute the
        // cell’s display width.
        let width = DisplayWidth::from(chars.len());

        TextCell {
            contents: chars.into(),
            width:    width,
        }
    }
}

impl f::Permissions {
    pub fn render(&self, colours: &Colours, x_colour: Style) -> Vec<ANSIString<'static>> {
        let bit = |bit, chr: &'static str, style: Style| {
            if bit { style.paint(chr) } else { colours.punctuation.paint("-") }
        };

        vec![
            bit(self.user_read,     "r", colours.perms.user_read),
            bit(self.user_write,    "w", colours.perms.user_write),
            bit(self.user_execute,  "x", x_colour),
            bit(self.group_read,    "r", colours.perms.group_read),
            bit(self.group_write,   "w", colours.perms.group_write),
            bit(self.group_execute, "x", colours.perms.group_execute),
            bit(self.other_read,    "r", colours.perms.other_read),
            bit(self.other_write,   "w", colours.perms.other_write),
            bit(self.other_execute, "x", colours.perms.other_execute),
        ]
    }
}

impl f::Type {
    pub fn render(&self, colours: &Colours) -> ANSIString<'static> {
        match *self {
            f::Type::File        => colours.filetypes.normal.paint("."),
            f::Type::Directory   => colours.filetypes.directory.paint("d"),
            f::Type::Pipe        => colours.filetypes.pipe.paint("|"),
            f::Type::Link        => colours.filetypes.symlink.paint("l"),
            f::Type::CharDevice  => colours.filetypes.device.paint("c"),
            f::Type::BlockDevice => colours.filetypes.device.paint("b"),
            f::Type::Socket      => colours.filetypes.socket.paint("s"),
            f::Type::Special     => colours.filetypes.special.paint("?"),
        }
    }
}

#[cfg(test)]
#[allow(unused_results)]
pub mod test {
    use output::details::Details;
    use output::cell::TextCellContents;
    use fs::fields as f;

    use ansi_term::Colour::*;

    #[test]
    fn negate() {
        let mut details = Details::default();
        details.colours.punctuation = Fixed(44).normal();

        let bits = f::Permissions {
            user_read:  false,  user_write:  false,  user_execute:  false,
            group_read: false,  group_write: false,  group_execute: false,
            other_read: false,  other_write: false,  other_execute: false,
        };

        let expected = TextCellContents::from(vec![
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
        ]);

        assert_eq!(expected, bits.render(&details.colours, Fixed(66).normal()).into())
    }

    #[test]
    fn affirm() {
        let mut details = Details::default();
        details.colours.perms.user_read    = Fixed(101).normal();
        details.colours.perms.user_write   = Fixed(102).normal();

        details.colours.perms.group_read    = Fixed(104).normal();
        details.colours.perms.group_write   = Fixed(105).normal();
        details.colours.perms.group_execute = Fixed(106).normal();

        details.colours.perms.other_read    = Fixed(107).normal();
        details.colours.perms.other_write   = Fixed(108).normal();
        details.colours.perms.other_execute = Fixed(109).normal();

        let bits = f::Permissions {
            user_read:  true,  user_write:  true,  user_execute:  true,
            group_read: true,  group_write: true,  group_execute: true,
            other_read: true,  other_write: true,  other_execute: true,
        };

        let expected = TextCellContents::from(vec![
            Fixed(101).paint("r"),  Fixed(102).paint("w"),  Fixed(103).paint("x"),
            Fixed(104).paint("r"),  Fixed(105).paint("w"),  Fixed(106).paint("x"),
            Fixed(107).paint("r"),  Fixed(108).paint("w"),  Fixed(109).paint("x"),
        ]);

        assert_eq!(expected, bits.render(&details.colours, Fixed(103).normal()).into())
    }
}
<commit_msg>Inline field<commit_after>use fs::fields as f;
use output::colours::Colours;
use output::cell::{TextCell, DisplayWidth};
use ansi_term::{ANSIString, Style};

impl f::PermissionsPlus {
    pub fn render(&self, colours: &Colours) -> TextCell {
        let x_colour = if self.file_type.is_regular_file() { colours.perms.user_execute_file }
                                                      else { colours.perms.user_execute_other };

        let mut chars = vec![ self.file_type.render(colours) ];
        chars.extend(self.permissions.render(colours, x_colour));

        if self.xattrs {
           chars.push(colours.perms.attribute.paint("@"));
        }

        // As these are all ASCII characters, we can guarantee that they’re
        // all going to be one character wide, and don’t need to compute the
        // cell’s display width.
        TextCell {
            width:    DisplayWidth::from(chars.len()),
            contents: chars.into(),
        }
    }
}

impl f::Permissions {
    pub fn render(&self, colours: &Colours, x_colour: Style) -> Vec<ANSIString<'static>> {
        let bit = |bit, chr: &'static str, style: Style| {
            if bit { style.paint(chr) } else { colours.punctuation.paint("-") }
        };

        vec![
            bit(self.user_read,     "r", colours.perms.user_read),
            bit(self.user_write,    "w", colours.perms.user_write),
            bit(self.user_execute,  "x", x_colour),
            bit(self.group_read,    "r", colours.perms.group_read),
            bit(self.group_write,   "w", colours.perms.group_write),
            bit(self.group_execute, "x", colours.perms.group_execute),
            bit(self.other_read,    "r", colours.perms.other_read),
            bit(self.other_write,   "w", colours.perms.other_write),
            bit(self.other_execute, "x", colours.perms.other_execute),
        ]
    }
}

impl f::Type {
    pub fn render(&self, colours: &Colours) -> ANSIString<'static> {
        match *self {
            f::Type::File        => colours.filetypes.normal.paint("."),
            f::Type::Directory   => colours.filetypes.directory.paint("d"),
            f::Type::Pipe        => colours.filetypes.pipe.paint("|"),
            f::Type::Link        => colours.filetypes.symlink.paint("l"),
            f::Type::CharDevice  => colours.filetypes.device.paint("c"),
            f::Type::BlockDevice => colours.filetypes.device.paint("b"),
            f::Type::Socket      => colours.filetypes.socket.paint("s"),
            f::Type::Special     => colours.filetypes.special.paint("?"),
        }
    }
}

#[cfg(test)]
#[allow(unused_results)]
pub mod test {
    use output::details::Details;
    use output::cell::TextCellContents;
    use fs::fields as f;

    use ansi_term::Colour::*;

    #[test]
    fn negate() {
        let mut details = Details::default();
        details.colours.punctuation = Fixed(44).normal();

        let bits = f::Permissions {
            user_read:  false,  user_write:  false,  user_execute:  false,
            group_read: false,  group_write: false,  group_execute: false,
            other_read: false,  other_write: false,  other_execute: false,
        };

        let expected = TextCellContents::from(vec![
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
            Fixed(44).paint("-"),  Fixed(44).paint("-"),  Fixed(44).paint("-"),
        ]);

        assert_eq!(expected, bits.render(&details.colours, Fixed(66).normal()).into())
    }

    #[test]
    fn affirm() {
        let mut details = Details::default();
        details.colours.perms.user_read    = Fixed(101).normal();
        details.colours.perms.user_write   = Fixed(102).normal();

        details.colours.perms.group_read    = Fixed(104).normal();
        details.colours.perms.group_write   = Fixed(105).normal();
        details.colours.perms.group_execute = Fixed(106).normal();

        details.colours.perms.other_read    = Fixed(107).normal();
        details.colours.perms.other_write   = Fixed(108).normal();
        details.colours.perms.other_execute = Fixed(109).normal();

        let bits = f::Permissions {
            user_read:  true,  user_write:  true,  user_execute:  true,
            group_read: true,  group_write: true,  group_execute: true,
            other_read: true,  other_write: true,  other_execute: true,
        };

        let expected = TextCellContents::from(vec![
            Fixed(101).paint("r"),  Fixed(102).paint("w"),  Fixed(103).paint("x"),
            Fixed(104).paint("r"),  Fixed(105).paint("w"),  Fixed(106).paint("x"),
            Fixed(107).paint("r"),  Fixed(108).paint("w"),  Fixed(109).paint("x"),
        ]);

        assert_eq!(expected, bits.render(&details.colours, Fixed(103).normal()).into())
    }
}
<|endoftext|>