<commit_before>use byteorder::{BigEndian, ByteOrder};
use std::io;

use super::datagram::{DatagramSender, MAX_DATAGRAM_LENGTH};

const HEADER_LENGTH: usize = 2;
const MAX_BLOCK_LENGTH: usize = HEADER_LENGTH + MAX_DATAGRAM_LENGTH;

const TAG: &'static str = "DatagramBuffer";

/// Circular buffer to store datagrams (preserving their boundaries).
///
/// ```text
///     circularBufferLength
/// |<------------------------->| extra space for storing the last datagram in one block
/// +---------------------------+------+
/// |                           |      |
/// |[D4]     [  D1  ][ D2 ][  D3  ]   |
/// +---------------------------+------+
///     ^     ^
///  head     tail
/// ```
pub struct DatagramBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
    circular_buffer_length: usize,
}

impl DatagramBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + MAX_BLOCK_LENGTH].into_boxed_slice(),
            head: 0,
            tail: 0,
            circular_buffer_length: capacity + 1,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    pub fn has_enough_space_for(&self, datagram_length: usize) -> bool {
        if self.head >= self.tail {
            // there is at least the extra space for storing 1 packet
            return true;
        }
        let remaining = self.tail - self.head + 1;
        HEADER_LENGTH + datagram_length < remaining
    }

    pub fn write_to<S: DatagramSender>(&mut self, destination: &mut S) -> io::Result<()> {
        let length = self.read_length() as usize;
        let source_slice = &self.buf[self.tail..self.tail + length];
        self.tail += length;
        if self.tail >= self.circular_buffer_length {
            self.tail = 0;
        }
        let w = destination.send(source_slice)?;
        if w != length {
            error!(target: TAG, "Cannot write the whole datagram to the buffer (only {}/{})", w, length);
            return Err(io::Error::new(io::ErrorKind::Other, "Cannot write the whole datagram"))
        }
        Ok(())
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        let length = source.len();
        assert!(length <= MAX_DATAGRAM_LENGTH, "Datagram length may not be greater than {} bytes", MAX_DATAGRAM_LENGTH);
        if !self.has_enough_space_for(length) {
            return Err(io::Error::new(io::ErrorKind::Other, "Datagram buffer is full"));
        }
        self.write_length(length as u16);
        let target_slice = &mut self.buf[self.head..self.head + length];
        target_slice.copy_from_slice(source);
        self.head += length;
        if self.head >= self.circular_buffer_length {
            self.head = 0;
        }
        Ok(())
    }

    fn read_length(&mut self) -> u16 {
        self.tail += 2;
        BigEndian::read_u16(&self.buf[self.tail - 2..self.tail])
    }

    fn write_length(&mut self, length: u16) {
        BigEndian::write_u16(&mut self.buf[self.head..self.head + 2], length);
        self.head += 2;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use relay::datagram::tests::MockDatagramSocket;

    fn create_datagram(length: u8) -> Vec<u8> {
        (0..length).collect()
    }

    #[test]
    fn bufferize_datagram() {
        let datagram = create_datagram(5);
        let mut datagram_buffer = DatagramBuffer::new(9);

        datagram_buffer.read_from(&datagram).unwrap();
        assert_eq!(read_datagram(&mut datagram_buffer), datagram);
    }

    #[test]
    fn split_datagrams_at_boundaries() {
        let mut datagram_buffer = DatagramBuffer::new(32);

        let datagram5 = create_datagram(5);
        let datagram0 = create_datagram(0);
        let datagram3 = create_datagram(3);
        let datagram4 = create_datagram(4);

        datagram_buffer.read_from(&datagram5).unwrap();
        datagram_buffer.read_from(&datagram0).unwrap();
        datagram_buffer.read_from(&datagram3).unwrap();
        datagram_buffer.read_from(&datagram4).unwrap();

        assert_eq!(read_datagram(&mut datagram_buffer), datagram5);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram0);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram3);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram4);
    }

    #[test]
    fn circular() {
        let datagram5 = create_datagram(5);
        let datagram3 = create_datagram(3);

        let mut datagram_buffer = DatagramBuffer::new(14);

        // write and consume 10 bytes
        datagram_buffer.read_from(&create_datagram(10)).unwrap();
        {
            // write and forget
            let mut mock = MockDatagramSocket::new();
            datagram_buffer.write_to(&mut mock).unwrap();
        }

        // DatagramBuffer is expected to store the whole datagram (even if it exceeds its "capacity")
        datagram_buffer.read_from(&datagram5).unwrap();
        datagram_buffer.read_from(&datagram3).unwrap();

        assert_eq!(read_datagram(&mut datagram_buffer), datagram5);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram3);
    }

    fn read_datagram(datagram_buffer: &mut DatagramBuffer) -> Vec<u8> {
        let mut mock = MockDatagramSocket::new();
        datagram_buffer.write_to(&mut mock).unwrap();
        mock.data().to_vec()
    }
}
<commit_msg>Add DatagramBuffer assertion<commit_after>use byteorder::{BigEndian, ByteOrder};
use std::io;

use super::datagram::{DatagramSender, MAX_DATAGRAM_LENGTH};

const HEADER_LENGTH: usize = 2;
const MAX_BLOCK_LENGTH: usize = HEADER_LENGTH + MAX_DATAGRAM_LENGTH;

const TAG: &'static str = "DatagramBuffer";

/// Circular buffer to store datagrams (preserving their boundaries).
///
/// ```text
///     circularBufferLength
/// |<------------------------->| extra space for storing the last datagram in one block
/// +---------------------------+------+
/// |                           |      |
/// |[D4]     [  D1  ][ D2 ][  D3  ]   |
/// +---------------------------+------+
///     ^     ^
///  head     tail
/// ```
pub struct DatagramBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
    circular_buffer_length: usize,
}

impl DatagramBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + MAX_BLOCK_LENGTH].into_boxed_slice(),
            head: 0,
            tail: 0,
            circular_buffer_length: capacity + 1,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    pub fn has_enough_space_for(&self, datagram_length: usize) -> bool {
        if self.head >= self.tail {
            // there is at least the extra space for storing 1 packet
            return true;
        }
        let remaining = self.tail - self.head + 1;
        HEADER_LENGTH + datagram_length < remaining
    }

    pub fn write_to<S: DatagramSender>(&mut self, destination: &mut S) -> io::Result<()> {
        assert!(!self.is_empty(), "DatagramBuffer.write_to() called while empty");
        let length = self.read_length() as usize;
        let source_slice = &self.buf[self.tail..self.tail + length];
        self.tail += length;
        if self.tail >= self.circular_buffer_length {
            self.tail = 0;
        }
        let w = destination.send(source_slice)?;
        if w != length {
            error!(target: TAG, "Cannot write the whole datagram to the buffer (only {}/{})", w, length);
            return Err(io::Error::new(io::ErrorKind::Other, "Cannot write the whole datagram"))
        }
        Ok(())
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        let length = source.len();
        assert!(length <= MAX_DATAGRAM_LENGTH, "Datagram length may not be greater than {} bytes", MAX_DATAGRAM_LENGTH);
        if !self.has_enough_space_for(length) {
            return Err(io::Error::new(io::ErrorKind::Other, "Datagram buffer is full"));
        }
        self.write_length(length as u16);
        let target_slice = &mut self.buf[self.head..self.head + length];
        target_slice.copy_from_slice(source);
        self.head += length;
        if self.head >= self.circular_buffer_length {
            self.head = 0;
        }
        Ok(())
    }

    fn read_length(&mut self) -> u16 {
        self.tail += 2;
        BigEndian::read_u16(&self.buf[self.tail - 2..self.tail])
    }

    fn write_length(&mut self, length: u16) {
        BigEndian::write_u16(&mut self.buf[self.head..self.head + 2], length);
        self.head += 2;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use relay::datagram::tests::MockDatagramSocket;

    fn create_datagram(length: u8) -> Vec<u8> {
        (0..length).collect()
    }

    #[test]
    fn bufferize_datagram() {
        let datagram = create_datagram(5);
        let mut datagram_buffer = DatagramBuffer::new(9);

        datagram_buffer.read_from(&datagram).unwrap();
        assert_eq!(read_datagram(&mut datagram_buffer), datagram);
    }

    #[test]
    fn split_datagrams_at_boundaries() {
        let mut datagram_buffer = DatagramBuffer::new(32);

        let datagram5 = create_datagram(5);
        let datagram0 = create_datagram(0);
        let datagram3 = create_datagram(3);
        let datagram4 = create_datagram(4);

        datagram_buffer.read_from(&datagram5).unwrap();
        datagram_buffer.read_from(&datagram0).unwrap();
        datagram_buffer.read_from(&datagram3).unwrap();
        datagram_buffer.read_from(&datagram4).unwrap();

        assert_eq!(read_datagram(&mut datagram_buffer), datagram5);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram0);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram3);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram4);
    }

    #[test]
    fn circular() {
        let datagram5 = create_datagram(5);
        let datagram3 = create_datagram(3);

        let mut datagram_buffer = DatagramBuffer::new(14);

        // write and consume 10 bytes
        datagram_buffer.read_from(&create_datagram(10)).unwrap();
        {
            // write and forget
            let mut mock = MockDatagramSocket::new();
            datagram_buffer.write_to(&mut mock).unwrap();
        }

        // DatagramBuffer is expected to store the whole datagram (even if it exceeds its "capacity")
        datagram_buffer.read_from(&datagram5).unwrap();
        datagram_buffer.read_from(&datagram3).unwrap();

        assert_eq!(read_datagram(&mut datagram_buffer), datagram5);
        assert_eq!(read_datagram(&mut datagram_buffer), datagram3);
    }

    fn read_datagram(datagram_buffer: &mut DatagramBuffer) -> Vec<u8> {
        let mut mock = MockDatagramSocket::new();
        datagram_buffer.write_to(&mut mock).unwrap();
        mock.data().to_vec()
    }
}
<|endoftext|>


<commit_before>//! Types for the [`m.room.join_rules`] event.
//!
//! [`m.room.join_rules`]: https://spec.matrix.org/v1.2/client-server-api/#mroomjoin_rules

use std::{borrow::Cow, collections::BTreeMap};

use ruma_events_macros::EventContent;
use ruma_identifiers::RoomId;
use ruma_serde::from_raw_json_value;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};

use crate::PrivOwnedStr;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(PrivOwnedStr),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => &rule.0,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(PrivOwnedStr(join_rule.into()))),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the room with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: Box<RoomId>) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: Box<RoomId>,
}

impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: Box<RoomId>) -> Self {
        Self { room_id }
    }
}

#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::room_id;

    use super::{AllowRule, JoinRule, RoomJoinRulesEventContent, SyncRoomJoinRulesEvent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[test]
    fn deserialize_restricted() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org").to_owned()),
                    AllowRule::room_membership(room_id!("!users:example.org").to_owned())
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    #[test]
    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<SyncRoomJoinRulesEvent>(json), Ok(_));
    }
}
<commit_msg>events: Update the description of JoinRule::Knock<commit_after>//! Types for the [`m.room.join_rules`] event.
//!
//! [`m.room.join_rules`]: https://spec.matrix.org/v1.2/client-server-api/#mroomjoin_rules

use std::{borrow::Cow, collections::BTreeMap};

use ruma_events_macros::EventContent;
use ruma_identifiers::RoomId;
use ruma_serde::from_raw_json_value;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};

use crate::PrivOwnedStr;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Users can join the room if they are invited, or they can request an invite to the room.
    ///
    /// They can be allowed (invited) or denied (kicked/banned) access.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(PrivOwnedStr),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => &rule.0,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(PrivOwnedStr(join_rule.into()))),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the room with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: Box<RoomId>) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: Box<RoomId>,
}

impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: Box<RoomId>) -> Self {
        Self { room_id }
    }
}

#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::room_id;

    use super::{AllowRule, JoinRule, RoomJoinRulesEventContent, SyncRoomJoinRulesEvent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[test]
    fn deserialize_restricted() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org").to_owned()),
                    AllowRule::room_membership(room_id!("!users:example.org").to_owned())
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    #[test]
    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<SyncRoomJoinRulesEvent>(json), Ok(_));
    }
}
<|endoftext|>


<commit_before>//! # The Lea Virtual Machine
//!
//! The VM executes Lea byte code generated by the emitter.
//!
//! # Calls
//!
//! Calls are recorded as `CallInfo`s inside a vector used as a stack. When a call instruction is
//! executed, the current instruction pointer and stack top is saved in a `CallInfo` struct, along
//! with the called function, and pushed onto the call stack.
//!
//! Then, the stack is extended by the (constant) number of stack slots needed, as stored in the
//! function prototype, and the call arguments are copied to the first slots. Depending on whether
//! a variable number of arguments was passed (as encoded in the call instruction) and whether the
//! callee accepts variable parameters, some of the arguments may be discarded or the stack may be
//! grown dynamically.
//!
//! When executing a return instruction, the current `CallInfo` is popped off the call stack and
//! the instruction pointer is restored. The returned values are then copied into the caller's
//! stack frame (the number - possibly dynamic - is encoded in the call instruction). The VM stack
//! is adjusted by truncating it to a length of `lasttop`, stored in the `CallInfo`.
//!
//! If the call stack is now empty, the main function of the program has just returned and the VM
//! will exit.
//!
//! Otherwise, the topmost `CallInfo` on the call stack is the caller of the function that just
//! returned.

// TODO tracing, when GC is possible

use lea_core::opcode::*;

use mem::{TracedRef, GcStrategy};
use function::{Function, FunctionProto, Upval};
use value::Value;
use error::VmResult;

use std::iter;

/// Contains information about a called Lea function.
pub struct CallInfo {
    /// The function active at this call level
    func: TracedRef<Function>,
    /// The instruction pointer (index)
    ip: usize,
    /// The index in the value stack that contains register 0 of this called function.
    bottom: usize,
    /// Dynamic stack top. This is updated any time an instruction that returns a variable number
    /// of results is executed and stores the stack slot of value *after* the last value returned
    /// by the instruction (so `dtop == 0` means that no results were returned).
    ///
    /// Unlike `bottom`, this is a relative index into the value stack and must be offset by adding
    /// `bottom` to it (use `reg_get` and `reg_set` to do this).
    dtop: u8,
}

/// A VM context. Holds a garbage collector that manages the program's memory, the stack used for
/// local and temporary variables, the callstack, etc.
pub struct VM<G: GcStrategy> {
    gc: G,
    main: TracedRef<Function>,
    /// Call stack
    calls: Vec<CallInfo>,
    /// "VM stack", "value stack" or just stack. Stores the activation of functions in the form of
    /// variables (registers) used by the function.
    stack: Vec<Value>,
}

impl<G: GcStrategy> VM<G> {
    pub fn new(gc: G, main: TracedRef<Function>) -> VM<G> {
        VM {
            gc: gc,
            main: main,
            calls: Vec::new(),
            stack: Vec::new(),
        }
    }

    /// Utility function that takes a main function as a `FunctionProto`, instantiates it and sets
    /// its first upvalue to `env`.
    pub fn with_env(mut gc: G, main: TracedRef<FunctionProto>, env: Value) -> VM<G> {
        // TODO mark this function unsafe?
        let mut first = true;
        let func = Function::new(&mut gc, main, |_| if first {
            first = false;
            Upval::Closed(env)
        } else {
            Upval::Closed(Value::TNil)
        });

        let mainref = gc.register_obj(func);
        VM::new(gc, mainref)
    }

    pub fn gc(&self) -> &G {
        &self.gc
    }

    pub fn gc_mut(&mut self) -> &mut G {
        &mut self.gc
    }

    /// Starts execution of the program. This may not be called multiple times on the same VM.
    ///
    /// Returns when the main function returns (or a runtime error occurs).
    pub fn start(&mut self) -> VmResult {
        // create initial CallInfo and run
        assert!(self.calls.is_empty());
        assert!(self.stack.is_empty());

        let main = self.main;
        self.push_call_to(main);
        self.run()
    }
}

// Private methods

impl<G: GcStrategy> VM<G> {
    /// Creates a `CallInfo` object that describes an activation of the given function and pushes
    /// it onto the callstack.
    ///
    /// This will also extend the value stack by the number of slots specified in the function
    /// prototype.
    fn push_call_to(&mut self, func: TracedRef<Function>) {
        let bottom = if self.calls.is_empty() { 0 } else {
            let call = self.cur_call();
            call.bottom + call.dtop as usize
        };
        let gc = &mut self.gc;
        let proto = unsafe {
            let proto = gc.get_mut(func).proto;
            gc.get_mut(proto)
        };

        // Ensure we have `proto.stacksize` slots free after current `dtop` (FIXME)
        // XXX is this optimized right?
        self.stack.extend(iter::repeat(Value::TNil).take(bottom + proto.stacksize as usize));

        self.calls.push(CallInfo {
            func: func,
            ip: 0,
            bottom: bottom,
            dtop: 0,
        });
    }

    fn cur_call(&self) -> &CallInfo {
        &self.calls[self.calls.len() - 1]
    }

    fn cur_call_mut(&mut self) -> &mut CallInfo {
        let lastidx = self.calls.len() - 1;
        &mut self.calls[lastidx]
    }

    fn cur_proto(&self) -> &FunctionProto {
        let call = self.cur_call();
        let func = unsafe { self.gc().get_ref(call.func) };

        unsafe { self.gc().get_ref(func.proto) }
    }

    /// Fetches the current opcode and increments the instruction pointer by 1
    fn fetch(&mut self) -> Opcode {
        let op = self.cur_proto().opcodes[self.cur_call().ip];
        self.cur_call_mut().ip += 1;
        op
    }

    /// Gets the value inside a register as specified in an opcode.
    fn reg_get(&self, reg: u8) -> Value {
        let bottom = self.cur_call().bottom;

        self.stack[bottom + reg as usize]
    }

    fn reg_set(&mut self, reg: u8, val: Value) {
        let bottom = self.cur_call().bottom;

        self.stack[bottom + reg as usize] = val;
    }

    /// VM main loop. This will start dispatching opcodes of the currently active function (at the
    /// top of the call stack).
    fn run(&mut self) -> VmResult {
        loop {
            let op = self.fetch();

            match op {
                LOADNIL(start, cnt) => {
                    // Set R[start] through R[start+count] to `nil`
                    for i in start..start+cnt+1 {
                        self.reg_set(i, Value::TNil);
                    }
                }
                MOV(to, from) => {
                    let val = self.reg_get(from);
                    self.reg_set(to, val);
                }
                RETURN(start, cnt) => {
                    let i = start;
                    let lim = if cnt == 0 {
                        debug!("dynamic ret from {} to {} (excl.)", start, self.cur_call().dtop);
                        self.cur_call().dtop
                    } else {
                        debug!("fixed ret from {} to {} (excl.)", start, cnt-1);
                        cnt-1
                    };

                    if self.calls.len() == 1 {
                        // main function exits
                        return Ok((i..lim).map(|i| self.reg_get(i)).collect())
                    } else {
                        unimplemented!();
                    }
                }
                _ => panic!("unimplemented opcode: {:?}", op),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use mem::noop::NoopGc;
    use function::FunctionProto;
    use value::Value;

    use lea_core::fndata::FnData;
    use lea_core::opcode::*;

    /// Defines a function. Evaluates to an `FnData` object.
    macro_rules! fndef {
        ( {
            stack: $stack:expr,
            fns: [ $( fn $fndef:tt, )* ],
            consts: [ $( $const_val:expr, )* ],
            ops: [ $( $ops:expr, )* ]
        } ) => {{
            FnData {
                stacksize: $stack,
                params: 0,      // TODO
                varargs: false, // TODO
                opcodes: Opcodes(vec![
                    $($ops,)*
                ]),
                consts: vec![ $( $const_val, )* ],
                upvals: Vec::new(), // TODO
                lines: Vec::new(),  // TODO
                source_name: String::new(), // TODO
                child_protos: vec![ $( Box::new(fndef!($fndef)), )* ],
            }
        }};
    }

    /// Defines a VM test. A main function definition is run, and the state of the VM compared to
    /// some expected values (in registers, with absolute index).
    macro_rules! test {
        ( $main:tt => [ $( $reg:tt : $val:expr, )* ] ) => {{
            let main: FnData = fndef!($main);
            let mut gc = NoopGc::default();
            let proto = FunctionProto::from_fndata(main, &mut gc);
            let mut vm = VM::with_env(gc, proto, Value::TNil);  // TODO
            vm.start().unwrap();

            // Compare VM's value stack with expected values
            $( assert_eq!(vm.stack[$reg], $val); )*
        }};
    }

    #[test] #[should_panic]
    fn meta() {
        test!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,1),
            ]
        } => [
            0: Value::TBool(true),
        ]);
    }

    #[test]
    fn simplest() {
        test!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,1),
            ]
        } => [
            0: Value::TNil,
        ]);
    }
}
<commit_msg>vm: add return test, impl loadbool<commit_after>//! # The Lea Virtual Machine
//!
//! The VM executes Lea byte code generated by the emitter.
//!
//! # Calls
//!
//! Calls are recorded as `CallInfo`s inside a vector used as a stack. When a call instruction is
//! executed, the current instruction pointer and stack top is saved in a `CallInfo` struct, along
//! with the called function, and pushed onto the call stack.
//!
//! Then, the stack is extended by the (constant) number of stack slots needed, as stored in the
//! function prototype, and the call arguments are copied to the first slots. Depending on whether
//! a variable number of arguments was passed (as encoded in the call instruction) and whether the
//! callee accepts variable parameters, some of the arguments may be discarded or the stack may be
//! grown dynamically.
//!
//! When executing a return instruction, the current `CallInfo` is popped off the call stack and
//! the instruction pointer is restored. The returned values are then copied into the caller's
//! stack frame (the number - possibly dynamic - is encoded in the call instruction). The VM stack
//! is adjusted by truncating it to a length of `lasttop`, stored in the `CallInfo`.
//!
//! If the call stack is now empty, the main function of the program has just returned and the VM
//! will exit.
//!
//! Otherwise, the topmost `CallInfo` on the call stack is the caller of the function that just
//! returned.

// TODO tracing, when GC is possible

use lea_core::opcode::*;

use mem::{TracedRef, GcStrategy};
use function::{Function, FunctionProto, Upval};
use value::Value;
use error::VmResult;

use std::iter;

/// Contains information about a called Lea function.
pub struct CallInfo {
    /// The function active at this call level
    func: TracedRef<Function>,
    /// The instruction pointer (index)
    ip: usize,
    /// The index in the value stack that contains register 0 of this called function.
    bottom: usize,
    /// Dynamic stack top. This is updated any time an instruction that returns a variable number
    /// of results is executed and stores the stack slot of value *after* the last value returned
    /// by the instruction (so `dtop == 0` means that no results were returned).
    ///
    /// Unlike `bottom`, this is a relative index into the value stack and must be offset by adding
    /// `bottom` to it (use `reg_get` and `reg_set` to do this).
    dtop: u8,
}

/// A VM context. Holds a garbage collector that manages the program's memory, the stack used for
/// local and temporary variables, the callstack, etc.
pub struct VM<G: GcStrategy> {
    gc: G,
    main: TracedRef<Function>,
    /// Call stack
    calls: Vec<CallInfo>,
    /// "VM stack", "value stack" or just stack. Stores the activation of functions in the form of
    /// variables (registers) used by the function.
    stack: Vec<Value>,
}

impl<G: GcStrategy> VM<G> {
    pub fn new(gc: G, main: TracedRef<Function>) -> VM<G> {
        VM {
            gc: gc,
            main: main,
            calls: Vec::new(),
            stack: Vec::new(),
        }
    }

    /// Utility function that takes a main function as a `FunctionProto`, instantiates it and sets
    /// its first upvalue to `env`.
    pub fn with_env(mut gc: G, main: TracedRef<FunctionProto>, env: Value) -> VM<G> {
        // TODO mark this function unsafe?
        let mut first = true;
        let func = Function::new(&mut gc, main, |_| if first {
            first = false;
            Upval::Closed(env)
        } else {
            Upval::Closed(Value::TNil)
        });

        let mainref = gc.register_obj(func);
        VM::new(gc, mainref)
    }

    pub fn gc(&self) -> &G {
        &self.gc
    }

    pub fn gc_mut(&mut self) -> &mut G {
        &mut self.gc
    }

    /// Starts execution of the program. This may not be called multiple times on the same VM.
    ///
    /// Returns when the main function returns (or a runtime error occurs).
    pub fn start(&mut self) -> VmResult {
        // create initial CallInfo and run
        assert!(self.calls.is_empty());
        assert!(self.stack.is_empty());

        let main = self.main;
        self.push_call_to(main);
        self.run()
    }
}

// Private methods

impl<G: GcStrategy> VM<G> {
    /// Creates a `CallInfo` object that describes an activation of the given function and pushes
    /// it onto the callstack.
    ///
    /// This will also extend the value stack by the number of slots specified in the function
    /// prototype.
    fn push_call_to(&mut self, func: TracedRef<Function>) {
        let bottom = if self.calls.is_empty() { 0 } else {
            let call = self.cur_call();
            call.bottom + call.dtop as usize
        };
        let gc = &mut self.gc;
        let proto = unsafe {
            let proto = gc.get_mut(func).proto;
            gc.get_mut(proto)
        };

        // Ensure we have `proto.stacksize` slots free after current `dtop` (FIXME)
        // XXX is this optimized right?
        self.stack.extend(iter::repeat(Value::TNil).take(bottom + proto.stacksize as usize));

        self.calls.push(CallInfo {
            func: func,
            ip: 0,
            bottom: bottom,
            dtop: 0,
        });
    }

    /// Called to return from a called Lea function (*not* from the main function). This pops the
    /// created `CallInfo` off the call stack and restores the value stack accordingly.
    ///
    /// This can not be called when the only active function is the program's main function.
    fn return_from_call(&mut self) {
        if self.calls.len() == 1 {
            panic!("return_from_call called while only main function is active");
        }

        unimplemented!();
    }

    fn cur_call(&self) -> &CallInfo {
        &self.calls[self.calls.len() - 1]
    }

    fn cur_call_mut(&mut self) -> &mut CallInfo {
        let lastidx = self.calls.len() - 1;
        &mut self.calls[lastidx]
    }

    fn cur_proto(&self) -> &FunctionProto {
        let call = self.cur_call();
        let func = unsafe { self.gc().get_ref(call.func) };

        unsafe { self.gc().get_ref(func.proto) }
    }

    /// Fetches the current opcode and increments the instruction pointer by 1
    fn fetch(&mut self) -> Opcode {
        let op = self.cur_proto().opcodes[self.cur_call().ip];
        self.cur_call_mut().ip += 1;
        op
    }

    /// Gets the value inside a register as specified in an opcode.
    fn reg_get(&self, reg: u8) -> Value {
        let bottom = self.cur_call().bottom;

        self.stack[bottom + reg as usize]
    }

    fn reg_set(&mut self, reg: u8, val: Value) {
        let bottom = self.cur_call().bottom;

        self.stack[bottom + reg as usize] = val;
    }

    /// VM main loop. This will start dispatching opcodes of the currently active function (at the
    /// top of the call stack).
    fn run(&mut self) -> VmResult {
        loop {
            let op = self.fetch();

            match op {
                LOADNIL(start, cnt) => {
                    // Set R[start] through R[start+count] to `nil`
                    for i in start..start+cnt+1 {
                        self.reg_set(i, Value::TNil);
                    }
                }
                LOADBOOL(start, cnt, val) => {
                    // Set R[start] through R[start+count] to `val` (true or false)
                    for i in start..start+cnt+1 {
                        self.reg_set(i, Value::TBool(val));
                    }
                }
                MOV(to, from) => {
                    let val = self.reg_get(from);
                    self.reg_set(to, val);
                }
                RETURN(start, cnt) => {
                    let i = start;
                    let lim = if cnt == 0 {
                        debug!("dynamic ret from {} to {} (excl.)", start, self.cur_call().dtop);
                        self.cur_call().dtop
                    } else {
                        debug!("fixed ret from {} to {} (excl.)", start, cnt-1);
                        cnt-1
                    };

                    if self.calls.len() == 1 {
                        // main function exits
                        return Ok((i..lim).map(|i| self.reg_get(i)).collect())
                    } else {
                        self.return_from_call();
                    }
                }
                _ => panic!("unimplemented opcode: {:?}", op),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use mem::noop::NoopGc;
    use function::FunctionProto;
    use value::Value;

    use lea_core::fndata::FnData;
    use lea_core::opcode::*;

    /// Defines a function. Evaluates to an `FnData` object.
    macro_rules! fndef {
        ( {
            stack: $stack:expr,
            fns: [ $( fn $fndef:tt, )* ],
            consts: [ $( $const_val:expr, )* ],
            ops: [ $( $ops:expr, )* ]
        } ) => {{
            FnData {
                stacksize: $stack,
                params: 0,      // TODO
                varargs: false, // TODO
                opcodes: Opcodes(vec![
                    $($ops,)*
                ]),
                consts: vec![ $( $const_val, )* ],
                upvals: Vec::new(), // TODO
                lines: Vec::new(),  // TODO
                source_name: String::new(), // TODO
                child_protos: vec![ $( Box::new(fndef!($fndef)), )* ],
            }
        }};
    }

    /// Runs a new VM instance with the given main function. Returns a tuple containing the VM and
    /// the `VmResult` returned by `vm.start()` (see `error.rs`).
    macro_rules! run {
        ( $main:tt ) => {{
            run!($main with Value::TNil)
        }};
        ( $main:tt with $env:expr ) => {{
            let main: FnData = fndef!($main);
            let mut gc = NoopGc::default();
            let proto = FunctionProto::from_fndata(main, &mut gc);
            let mut vm = VM::with_env(gc, proto, $env);
            let ret = vm.start();

            (vm, ret)
        }};
    }

    /// Runs a main function and compares the returned values (or VM error).
    macro_rules! test_ret {
        ( $main:tt => return [ $($val:expr),* ] ) => {{
            let (_, ret) = run!($main);

            assert_eq!(ret.unwrap(), [ $($val,)* ]);
        }};
    }

    /// Defines a VM test. A main function definition is run, and the state of the VM compared to
    /// some expected values (in registers, with absolute index).
    macro_rules! test_regs {
        ( $main:tt => [ $( $reg:tt : $val:expr, )* ] ) => {{
            let (vm, _) = run!($main);

            // Compare VM's value stack with expected values
            $( assert_eq!(vm.stack[$reg], $val); )*
        }};
    }

    #[test] #[should_panic]
    fn meta() {
        test_regs!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,1),
            ]
        } => [
            0: Value::TBool(true),
        ]);
    }

    #[test] #[should_panic]
    fn stack_too_small() {
        run!({
            stack: 2,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,2),   // writes 0, 1, 2
                RETURN(0,1),
            ]
        });
    }

    #[test]
    fn simplest() {
        test_regs!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,1),
            ]
        } => [
            0: Value::TNil,
        ]);
    }

    #[test] #[should_panic]
    fn test_ret_panic() {
        test_ret!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,2),
            ]
        } => return [ Value::TInt(4) ]);
    }

    #[test]
    fn test_ret() {
        test_ret!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,1),
            ]
        } => return [ ]);
        test_ret!({
            stack: 1,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,0),
                RETURN(0,2),
            ]
        } => return [ Value::TNil ]);
        test_ret!({
            stack: 4,
            fns: [],
            consts: [],
            ops: [
                LOADNIL(0,3),
                LOADBOOL(2,0,true),
                LOADBOOL(3,0,false),
                RETURN(0,5),
            ]
        } => return [ Value::TNil, Value::TNil, Value::TBool(true), Value::TBool(false) ]);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
// Copyright (c) 2019-2021 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0

//! Interface wrappers to C API entering to the bootloader

use crate::area::AreaDesc;
use simflash::SimMultiFlash;
use crate::api;

/// The result of an invocation of `boot_go`.  This is intentionally opaque so that we can provide
/// accessors for everything we need from this.
#[derive(Debug)]
pub enum BootGoResult {
    /// This run was stopped by the flash simulation mechanism.
    Stopped,
    /// The bootloader ran to completion with the following data.
    Normal {
        result: i32,
        asserts: u8,
    },
}

impl BootGoResult {
    /// Was this run interrupted.
    pub fn interrupted(&self) -> bool {
        matches!(self, BootGoResult::Stopped)
    }

    /// Was this boot run successful (returned 0)
    pub fn success(&self) -> bool {
        matches!(self, BootGoResult::Normal { result: 0, .. })
    }

    /// Success, but also no asserts.
    pub fn success_no_asserts(&self) -> bool {
        matches!(self, BootGoResult::Normal {
            result: 0,
            asserts: 0,
        })
    }

    /// Get the asserts count.  An interrupted run will be considered to have no asserts.
    pub fn asserts(&self) -> u8 {
        match self {
            BootGoResult::Normal { asserts, .. } => *asserts,
            _ => 0,
        }
    }
}

/// Invoke the bootloader on this flash device.
pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
               counter: Option<&mut i32>, catch_asserts: bool) -> BootGoResult {
    for (&dev_id, flash) in multiflash.iter_mut() {
        api::set_flash(dev_id, flash);
    }
    let mut sim_ctx = api::CSimContext {
        flash_counter: match counter {
            None => 0,
            Some(ref c) => **c as libc::c_int
        },
        jumped: 0,
        c_asserts: 0,
        c_catch_asserts: if catch_asserts { 1 } else { 0 },
        boot_jmpbuf: [0; 16],
    };
    let mut rsp = api::BootRsp {
        br_hdr: std::ptr::null(),
        flash_dev_id: 0,
        image_off: 0,
    };
    let result = unsafe {
        raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _,
            &mut rsp as *mut _) as i32
    };
    let asserts = sim_ctx.c_asserts;
    if let Some(c) = counter {
        *c = sim_ctx.flash_counter;
    }
    for &dev_id in multiflash.keys() {
        api::clear_flash(dev_id);
    }
    if result == -0x13579 {
        BootGoResult::Stopped
    } else {
        BootGoResult::Normal { result, asserts }
    }
}

pub fn boot_trailer_sz(align: u32) -> u32 {
    unsafe { raw::boot_trailer_sz(align) }
}

pub fn boot_status_sz(align: u32) -> u32 {
    unsafe { raw::boot_status_sz(align) }
}

pub fn boot_magic_sz() -> usize {
    unsafe { raw::boot_magic_sz() as usize }
}

pub fn boot_max_align() -> usize {
    unsafe { raw::boot_max_align() as usize }
}

pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
    unsafe {
        let mut encbuf: [u8; 256] = [0; 256];
        if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
                                  seckey.as_ptr(), seckey.len() as u32,
                                  encbuf.as_mut_ptr()) == 0 {
            return Ok(encbuf);
        }
        Err("Failed to encrypt buffer")
    }
}

pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
    unsafe {
        let mut encbuf = vec![0u8; 24];
        if keylen == 32 {
            encbuf = vec![0u8; 40];
        }
        if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
            return Ok(encbuf);
        }
        Err("Failed to encrypt buffer")
    }
}

mod raw {
    use crate::area::CAreaDesc;
    use crate::api::{BootRsp, CSimContext};

    extern "C" {
        // This generates a warning about `CAreaDesc` not being foreign safe.  There doesn't appear to
        // be any way to get rid of this warning.  See https://github.com/rust-lang/rust/issues/34798
        // for information and tracking.
        pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
            rsp: *mut BootRsp) -> libc::c_int;

        pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
        pub fn boot_status_sz(min_write_sz: u32) -> u32;

        pub fn boot_magic_sz() -> u32;
        pub fn boot_max_align() -> u32;

        pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
                                 seckey: *const u8, seckey_len: libc::c_uint,
                                 encbuf: *mut u8) -> libc::c_int;

        pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
                           encbuf: *mut u8) -> libc::c_int;
    }
}
<commit_msg>sim: Allow access to the boot response<commit_after>// Copyright (c) 2017-2019 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
// Copyright (c) 2019-2021 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0

//! Interface wrappers to C API entering to the bootloader

use crate::area::AreaDesc;
use simflash::SimMultiFlash;
use crate::api;

/// The result of an invocation of `boot_go`.  This is intentionally opaque so that we can provide
/// accessors for everything we need from this.
#[derive(Debug)]
pub enum BootGoResult {
    /// This run was stopped by the flash simulation mechanism.
    Stopped,
    /// The bootloader ran to completion with the following data.
    Normal {
        result: i32,
        asserts: u8,

        resp: api::BootRsp,
    },
}

impl BootGoResult {
    /// Was this run interrupted.
    pub fn interrupted(&self) -> bool {
        matches!(self, BootGoResult::Stopped)
    }

    /// Was this boot run successful (returned 0)
    pub fn success(&self) -> bool {
        matches!(self, BootGoResult::Normal { result: 0, .. })
    }

    /// Success, but also no asserts.
    pub fn success_no_asserts(&self) -> bool {
        matches!(self, BootGoResult::Normal {
            result: 0,
            asserts: 0,
            ..
        })
    }

    /// Get the asserts count.  An interrupted run will be considered to have no asserts.
    pub fn asserts(&self) -> u8 {
        match self {
            BootGoResult::Normal { asserts, .. } => *asserts,
            _ => 0,
        }
    }

    /// Retrieve the 'resp' field that is filled in.
    pub fn resp(&self) -> Option<&api::BootRsp> {
        match self {
            BootGoResult::Normal { resp, .. } => Some(resp),
            _ => None,
        }
    }
}

/// Invoke the bootloader on this flash device.
pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
               counter: Option<&mut i32>, catch_asserts: bool) -> BootGoResult {
    for (&dev_id, flash) in multiflash.iter_mut() {
        api::set_flash(dev_id, flash);
    }
    let mut sim_ctx = api::CSimContext {
        flash_counter: match counter {
            None => 0,
            Some(ref c) => **c as libc::c_int
        },
        jumped: 0,
        c_asserts: 0,
        c_catch_asserts: if catch_asserts { 1 } else { 0 },
        boot_jmpbuf: [0; 16],
    };
    let mut rsp = api::BootRsp {
        br_hdr: std::ptr::null(),
        flash_dev_id: 0,
        image_off: 0,
    };
    let result = unsafe {
        raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _,
            &mut rsp as *mut _) as i32
    };
    let asserts = sim_ctx.c_asserts;
    if let Some(c) = counter {
        *c = sim_ctx.flash_counter;
    }
    for &dev_id in multiflash.keys() {
        api::clear_flash(dev_id);
    }
    if result == -0x13579 {
        BootGoResult::Stopped
    } else {
        BootGoResult::Normal { result, asserts, resp: rsp }
    }
}

pub fn boot_trailer_sz(align: u32) -> u32 {
    unsafe { raw::boot_trailer_sz(align) }
}

pub fn boot_status_sz(align: u32) -> u32 {
    unsafe { raw::boot_status_sz(align) }
}

pub fn boot_magic_sz() -> usize {
    unsafe { raw::boot_magic_sz() as usize }
}

pub fn boot_max_align() -> usize {
    unsafe { raw::boot_max_align() as usize }
}

pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
    unsafe {
        let mut encbuf: [u8; 256] = [0; 256];
        if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
                                  seckey.as_ptr(), seckey.len() as u32,
                                  encbuf.as_mut_ptr()) == 0 {
            return Ok(encbuf);
        }
        Err("Failed to encrypt buffer")
    }
}

pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
    unsafe {
        let mut encbuf = vec![0u8; 24];
        if keylen == 32 {
            encbuf = vec![0u8; 40];
        }
        if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
            return Ok(encbuf);
        }
        Err("Failed to encrypt buffer")
    }
}

mod raw {
    use crate::area::CAreaDesc;
    use crate::api::{BootRsp, CSimContext};

    extern "C" {
        // This generates a warning about `CAreaDesc` not being foreign safe.  There doesn't appear to
        // be any way to get rid of this warning.  See https://github.com/rust-lang/rust/issues/34798
        // for information and tracking.
        pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
            rsp: *mut BootRsp) -> libc::c_int;

        pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
        pub fn boot_status_sz(min_write_sz: u32) -> u32;

        pub fn boot_magic_sz() -> u32;
        pub fn boot_max_align() -> u32;

        pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
                                 seckey: *const u8, seckey_len: libc::c_uint,
                                 encbuf: *mut u8) -> libc::c_int;

        pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
                           encbuf: *mut u8) -> libc::c_int;
    }
}
<|endoftext|>


<commit_before>extern crate immortal;
extern crate getopts;
extern crate time;

use immortal::scan;
use getopts::Options;
use std::env;
use std::thread;
use std::time::Duration;
use time::now_utc;

fn print_usage(program: &str, opts: Options) {
    let m = format!("usage: {} dir\n\n    dir    The directory that will be scanned.", program);
    print!("{}", opts.usage(&m));
}

fn main() {
    let version = env!("CARGO_PKG_VERSION");
    let args: Vec<String> = env::args().collect();
    let program = &args[0];
    let mut opts = Options::new();

    opts.optflag("v", "version", &format!("Print version: {}", version));

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(_) => {
            print_usage(&program, opts);
            return;
        }
    };

    if matches.opt_present("v") {
        println!("{}", version);
        return;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let sd = match scan::Scandir::new(&input, 5) {
        Err(_) => {
            println!("No such file or directory");
            return;
        },
        Ok(val) => val
    };

    println!("Scandir: {}", sd.path.display());
    sd.scan();

    // repeat every 5 seconds
    loop {
        println!("{}", now_utc().rfc3339());
        thread::sleep(Duration::new(sd.interval, 0));
        sd.scan();
    }
}
<commit_msg>sync Tue Nov 19 22:51:13 CET 2019<commit_after>fn main() {
    println!("immortaldir");
}
<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::Hash;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: uint,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> uint {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = &self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>uint -> usize<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::Hash;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 {
        if k_i < 2 {
            let sip = &self.sips[k_i as usize];
            let hash = sip.hash(item);
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>fn main() {
    let mut user_instance = User {
        username: String::from("userrrr"),
        email: String::from("mail@mail.com"),
        sign_in_count: 0,
        active: true
    };

    user_instance.sign_in_count = 1;

    println!("User sign in count: {}", user_instance.sign_in_count);
}

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool
}
<commit_msg>Example of field init shorthand<commit_after>fn main() {
    let mut user_instance = User {
        username: String::from("userrrr"),
        email: String::from("mail@mail.com"),
        sign_in_count: 0,
        active: true
    };

    user_instance.sign_in_count = 1;

    println!("User sign in count: {}", user_instance.sign_in_count);

    let built_user = build_user(
        String::from("mail@mail2.com"),
        String::from("mickey mouse")
    );
}

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        sign_in_count: 0,
        active: false
    }
}

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::io::{BufReader,BufRead};
use std::fs::File;

fn fuel_calc_v2(score: f32, debug: bool) -> f32 {
    let mut fuel_req = (score / 3.0).floor() - 2.0;
    if fuel_req < 0.0 {
        return 0.0;
    }
    fuel_req += fuel_calc_v2(fuel_req, false);
    if debug {
        println!("{} requires {} fuel", score, fuel_req);
    }
    fuel_req
}

fn fuel_calc_v1(score: f32, debug: bool) -> f32 {
    let fuel_req = (score / 3.0).floor() - 2.0;
    if debug {
        println!("{} requires {} fuel", score, fuel_req);
    }
    fuel_req as f32
}

fn solve(path: &Path, fuel_calc: fn(f32, bool) -> f32, debug: bool) -> u32{
    let display = path.display();
    let file = match File::open(&path) {
        Err(why) => panic!(
            "couldn't open {}: {}", display, why),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
    let scores = reader.lines().map(|line| {
        let score: f32 = line.unwrap().parse().unwrap();
        score
    });
    let fuel_reqs = scores.map(|score| {
        fuel_calc(score, debug) as u32
    });
    let total : u32 = fuel_reqs.sum();
    return total;
}

fn main() {
    for (idx, func) in [fuel_calc_v1, fuel_calc_v2].iter().enumerate() {
        println!("======Part {}=====", idx+1);
        println!("==Test Case==");
        let mut answer : u32 = solve(Path::new("./test"), *func, true);
        println!("Total Fuel Requirements: {}", answer);
        println!("==Real Thing==");
        answer = solve(Path::new("./input"), *func, false);
        println!("Total Fuel Requirements: {}", answer);
    }
}
<commit_msg>Refactor 2019 Day 01<commit_after>use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;

fn fuel_calc_v2(score: i32) -> i32 {
    let fuel_req = fuel_calc_v1(score);
    if fuel_req < 0 {
        return 0;
    }
    fuel_req + fuel_calc_v2(fuel_req)
}

fn fuel_calc_v1(score: i32) -> i32 {
    (score as f32 / 3.0).floor() as i32 - 2
}

fn solve(path: &Path, fuel_calc: fn(i32) -> i32, verbose: bool) -> i32 {
    let display = path.display();
    let file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, why),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
    let scores = reader.lines().map(|line| {
        line.unwrap().parse::<i32>().unwrap()
    });
    let fuel_reqs = scores.map(|score| {
        let fuel_req = fuel_calc(score);
        if verbose {
            println!("{} requires {} fuel", score, fuel_req);
        }
        fuel_req
    });
    fuel_reqs.sum()
}

fn main() {
    for (name, path, verbose) in [
        ("Test", Path::new("./test"), true),
        ("Real", Path::new("./input"), false),
    ]
    .iter()
    {
        println!("======={} Case=======", name);
        for (idx, func) in [fuel_calc_v1, fuel_calc_v2].iter().enumerate() {
            println!("==Part {}==", idx + 1);
            println!("Total Fuel Requirements: {}", solve(path, *func, *verbose));
        }
    }
}
<|endoftext|>


<commit_before>//! A map data type which allows the same key to exist at multiple scope levels
use std::borrow::Borrow;
use std::collections::hash_map::{self, IterMut};
use std::fmt;
use std::hash::Hash;

use crate::fnv::FnvMap;

/// A map struct which allows for the introduction of different scopes
/// Introducing a new scope will make it possible to introduce additional
/// variables with names already defined, shadowing the old name
/// After exiting a scope the shadowed variable will again be re introduced
pub struct ScopedMap<K: Eq + Hash, V> {
    /// A hashmap storing a key -> value mapping
    /// Stores a vector of values in which the value at the top is value returned from 'get'
    map: FnvMap<K, Vec<V>>,
    /// A vector of scopes, when entering a scope, None is added as a marker
    /// when later exiting a scope, values are removed from the map until the marker is found
    scopes: Vec<Option<K>>,
}

impl<K: Eq + Hash, V> Default for ScopedMap<K, V> {
    fn default() -> Self {
        ScopedMap {
            map: FnvMap::default(),
            scopes: Vec::default(),
        }
    }
}

impl<K, V> fmt::Debug for ScopedMap<K, V>
where
    K: Eq + Hash + fmt::Debug + Clone,
    V: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_map().entries(self.iter()).finish()
    }
}

#[allow(dead_code)]
impl<K: Eq + Hash + Clone, V> ScopedMap<K, V> {
    pub fn new() -> ScopedMap<K, V> {
        ScopedMap::default()
    }

    /// Introduces a new scope
    pub fn enter_scope(&mut self) {
        self.scopes.push(None);
    }

    pub fn current_scope(&self) -> impl Iterator<Item = (&K, &V)> {
        self.scopes
            .iter()
            .rev()
            .take_while(|scope| scope.is_some())
            .map(move |scope| {
                let key = scope.as_ref().unwrap();
                let value = self.map.get(key).and_then(|x| x.last()).expect("Value");
                (key, value)
            })
    }

    /// Exits the current scope, returning an iterator over the (key, value) pairs that are removed
    /// When `ExitScopeIter` is dropped any remaining pairs of the scope is removed as well.
    pub fn exit_scope(&mut self) -> ExitScopeIter<K, V> {
        ExitScopeIter {
            map: self,
            done: false,
        }
    }

    /// Removes a previously inserted value from the map.
    pub fn remove<Q>(&mut self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
        K: ::std::fmt::Debug,
        V: ::std::fmt::Debug,
    {
        match self.map.get_mut(k).map(|x| x.pop()) {
            Some(..) => {
                let mut i = self.scopes.len() as isize - 1;
                while i >= 0 {
                    if self.scopes[i as usize]
                        .as_ref()
                        .map_or(false, |x| x.borrow() == k)
                    {
                        self.scopes.remove(i as usize);
                    }
                    i -= 1;
                }
                true
            }
            None => false,
        }
    }

    /// Returns true if the key has a value declared in the last declared scope
    pub fn in_current_scope<Q>(&self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        for n in self.scopes.iter().rev() {
            match *n {
                Some(ref name) if name.borrow() == k => return true,
                None => break,
                _ => (),
            }
        }
        false
    }

    /// Returns a reference to the last inserted value corresponding to the key
    pub fn get<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a V>
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map.get(k).and_then(|x| x.last())
    }

    /// Returns a reference to the all inserted value corresponding to the key
    pub fn get_all<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a [V]>
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map.get(k).map(|x| &x[..])
    }

    pub fn entry(&mut self, key: K) -> Entry<K, V> {
        match self.map.entry(key) {
            hash_map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry(entry)),
            hash_map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry(entry)),
        }
    }

    pub fn contains_key<'a, Q: ?Sized>(&'a self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.get(k).is_some()
    }

    /// Returns the number of elements in the container.
    /// Shadowed elements are not counted
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns true if this map is empty
    pub fn is_empty(&self) -> bool {
        self.map.len() == 0
    }

    /// Removes all elements
    pub fn clear(&mut self) {
        self.map.clear();
        self.scopes.clear();
    }

    /// Swaps the value stored at key, or inserts it if it is not present
    pub fn swap(&mut self, k: K, v: V) -> Option<V> {
        let vec = match self.map.entry(k.clone()) {
            hash_map::Entry::Occupied(v) => v.into_mut(),
            hash_map::Entry::Vacant(v) => v.insert(Vec::new()),
        };
        if vec.is_empty() {
            vec.push(v);
            self.scopes.push(Some(k));
            None
        } else {
            let r = vec.pop();
            vec.push(v);
            r
        }
    }

    pub fn pop(&mut self, k: &K) -> Option<V> {
        match self.map.get_mut(k).and_then(|x| x.pop()) {
            Some(v) => {
                let mut i = self.scopes.len() as isize - 1;
                while i >= 0 {
                    if self.scopes[i as usize].as_ref().map_or(false, |x| x == k) {
                        self.scopes.remove(i as usize);
                    }
                    i -= 1;
                }
                Some(v)
            }
            None => None,
        }
    }

    pub fn get_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> {
        self.map.get_mut(key).and_then(|x| {
            let last = x.len() - 1;
            x.get_mut(last)
        })
    }

    pub fn insert(&mut self, k: K, v: V) -> bool {
        let vec = match self.map.entry(k.clone()) {
            hash_map::Entry::Occupied(v) => v.into_mut(),
            hash_map::Entry::Vacant(v) => v.insert(Vec::new()),
        };
        vec.push(v);
        self.scopes.push(Some(k));
        vec.len() == 1
    }
}

impl<K: Eq + Hash, V> ScopedMap<K, V> {
    /// Returns an iterator of the (key, values) pairs inserted in the map
    pub fn iter_mut(&mut self) -> IterMut<K, Vec<V>> {
        self.map.iter_mut()
    }

    pub fn iter(&self) -> Iter<K, V> {
        Iter {
            iter: self.map.iter(),
        }
    }
}

impl<K: Eq + Hash + Clone, V> Extend<(K, V)> for ScopedMap<K, V> {
    fn extend<T>(&mut self, iter: T)
    where
        T: IntoIterator<Item = (K, V)>,
    {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

pub enum Entry<'a, K, V> {
    Vacant(VacantEntry<'a, K, V>),
    Occupied(OccupiedEntry<'a, K, V>),
}

pub struct VacantEntry<'a, K, V>(hash_map::VacantEntry<'a, K, Vec<V>>);
pub struct OccupiedEntry<'a, K, V>(hash_map::OccupiedEntry<'a, K, Vec<V>>);

impl<'a, K, V> VacantEntry<'a, K, V> {
    pub fn insert(self, value: V) -> &'a mut V {
        &mut self.0.insert(vec![value])[0]
    }
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
    pub fn key(&self) -> &K {
        self.0.key()
    }

    pub fn get(&self) -> &V {
        self.0.get().last().unwrap()
    }

    pub fn get_mut(&mut self) -> &mut V {
        self.0.get_mut().last_mut().unwrap()
    }

    pub fn into_mut(self) -> &'a mut V {
        self.0.into_mut().last_mut().unwrap()
    }

    pub fn insert(&mut self, value: V) {
        self.0.get_mut().push(value);
    }
}

pub struct Iter<'a, K, V>
where
    K: 'a,
    V: 'a,
{
    iter: hash_map::Iter<'a, K, Vec<V>>,
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: 'a,
    V: 'a,
{
    type Item = (&'a K, &'a V);

    fn next(&mut self) -> Option<(&'a K, &'a V)> {
        loop {
            match self.iter.next() {
                Some((k, vs)) => {
                    if let Some(v) = vs.last() {
                        return Some((k, v));
                    }
                }
                None => return None,
            }
        }
    }
}

pub struct ExitScopeIter<'a, K, V>
where
    K: 'a + Eq + Hash + Clone,
    V: 'a,
{
    map: &'a mut ScopedMap<K, V>,
    done: bool,
}

impl<'a, K, V> Drop for ExitScopeIter<'a, K, V>
where
    K: Eq + Hash + Clone,
{
    fn drop(&mut self) {
        for _ in self {}
    }
}

impl<'a, K, V> Iterator for ExitScopeIter<'a, K, V>
where
    K: Eq + Hash + Clone,
{
    type Item = (K, V);

    fn next(&mut self) -> Option<Self::Item> {
        if self.done {
            None
        } else {
            match self.map.scopes.pop() {
                Some(Some(key)) => {
                    let result = self.map.map.get_mut(&key).and_then(|x| x.pop());
                    self.done = result.is_none();
                    result.map(|value| (key, value))
                }
                _ => {
                    self.done = true;
                    None
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let mut map = ScopedMap::new();
        map.insert("a", 0);
        map.insert("b", 1);
        map.enter_scope();
        assert_eq!(map.get(&"a"), Some(&0));
        assert_eq!(map.get(&"b"), Some(&1));
        assert_eq!(map.get(&"c"), None);
        map.insert("a", 1);
        map.insert("c", 2);
        assert_eq!(map.get(&"a"), Some(&1));
        assert_eq!(map.get(&"c"), Some(&2));
        map.exit_scope();
        assert_eq!(map.get(&"a"), Some(&0));
        assert_eq!(map.get(&"c"), None);
    }
}
<commit_msg>refactor(base): Simplify ScopedMap sightly<commit_after>//! A map data type which allows the same key to exist at multiple scope levels
use std::borrow::Borrow;
use std::collections::hash_map::{self, IterMut};
use std::fmt;
use std::hash::Hash;

use crate::fnv::FnvMap;

/// A map struct which allows for the introduction of different scopes
/// Introducing a new scope will make it possible to introduce additional
/// variables with names already defined, shadowing the old name
/// After exiting a scope the shadowed variable will again be re introduced
pub struct ScopedMap<K: Eq + Hash, V> {
    /// A hashmap storing a key -> value mapping
    /// Stores a vector of values in which the value at the top is value returned from 'get'
    map: FnvMap<K, Vec<V>>,
    /// A vector of scopes, when entering a scope, None is added as a marker
    /// when later exiting a scope, values are removed from the map until the marker is found
    scopes: Vec<Option<K>>,
}

impl<K: Eq + Hash, V> Default for ScopedMap<K, V> {
    fn default() -> Self {
        ScopedMap {
            map: FnvMap::default(),
            scopes: Vec::default(),
        }
    }
}

impl<K, V> fmt::Debug for ScopedMap<K, V>
where
    K: Eq + Hash + fmt::Debug + Clone,
    V: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_map().entries(self.iter()).finish()
    }
}

#[allow(dead_code)]
impl<K: Eq + Hash + Clone, V> ScopedMap<K, V> {
    pub fn new() -> ScopedMap<K, V> {
        ScopedMap::default()
    }

    /// Introduces a new scope
    pub fn enter_scope(&mut self) {
        self.scopes.push(None);
    }

    pub fn current_scope(&self) -> impl Iterator<Item = (&K, &V)> {
        self.scopes
            .iter()
            .rev()
            .take_while(|scope| scope.is_some())
            .map(move |scope| {
                let key = scope.as_ref().unwrap();
                let value = self.map.get(key).and_then(|x| x.last()).expect("Value");
                (key, value)
            })
    }

    /// Exits the current scope, returning an iterator over the (key, value) pairs that are removed
    /// When `ExitScopeIter` is dropped any remaining pairs of the scope is removed as well.
    pub fn exit_scope(&mut self) -> ExitScopeIter<K, V> {
        ExitScopeIter {
            map: self,
            done: false,
        }
    }

    /// Removes a previously inserted value from the map.
    pub fn remove<Q>(&mut self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
        K: ::std::fmt::Debug,
        V: ::std::fmt::Debug,
    {
        match self.map.get_mut(k).map(|x| x.pop()) {
            Some(..) => {
                let mut i = self.scopes.len() as isize - 1;
                while i >= 0 {
                    if self.scopes[i as usize]
                        .as_ref()
                        .map_or(false, |x| x.borrow() == k)
                    {
                        self.scopes.remove(i as usize);
                    }
                    i -= 1;
                }
                true
            }
            None => false,
        }
    }

    /// Returns true if the key has a value declared in the last declared scope
    pub fn in_current_scope<Q>(&self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        for n in self.scopes.iter().rev() {
            match *n {
                Some(ref name) if name.borrow() == k => return true,
                None => break,
                _ => (),
            }
        }
        false
    }

    /// Returns a reference to the last inserted value corresponding to the key
    pub fn get<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a V>
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map.get(k).and_then(|x| x.last())
    }

    /// Returns a reference to the all inserted value corresponding to the key
    pub fn get_all<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a [V]>
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map.get(k).map(|x| &x[..])
    }

    pub fn entry(&mut self, key: K) -> Entry<K, V> {
        match self.map.entry(key) {
            hash_map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry(entry)),
            hash_map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry(entry)),
        }
    }

    pub fn contains_key<'a, Q: ?Sized>(&'a self, k: &Q) -> bool
    where
        K: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.get(k).is_some()
    }

    /// Returns the number of elements in the container.
    /// Shadowed elements are not counted
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns true if this map is empty
    pub fn is_empty(&self) -> bool {
        self.map.len() == 0
    }

    /// Removes all elements
    pub fn clear(&mut self) {
        self.map.clear();
        self.scopes.clear();
    }

    /// Swaps the value stored at key, or inserts it if it is not present
    pub fn swap(&mut self, k: K, v: V) -> Option<V> {
        let vec = self.map.entry(k.clone()).or_default();
        if vec.is_empty() {
            vec.push(v);
            self.scopes.push(Some(k));
            None
        } else {
            let r = vec.pop();
            vec.push(v);
            r
        }
    }

    pub fn pop(&mut self, k: &K) -> Option<V> {
        match self.map.get_mut(k).and_then(|x| x.pop()) {
            Some(v) => {
                let mut i = self.scopes.len() as isize - 1;
                while i >= 0 {
                    if self.scopes[i as usize].as_ref().map_or(false, |x| x == k) {
                        self.scopes.remove(i as usize);
                    }
                    i -= 1;
                }
                Some(v)
            }
            None => None,
        }
    }

    pub fn get_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> {
        self.map.get_mut(key).and_then(|x| {
            let last = x.len() - 1;
            x.get_mut(last)
        })
    }

    pub fn insert(&mut self, k: K, v: V) -> bool {
        let vec = self.map.entry(k.clone()).or_default();
        vec.push(v);
        self.scopes.push(Some(k));
        vec.len() == 1
    }
}

impl<K: Eq + Hash, V> ScopedMap<K, V> {
    /// Returns an iterator of the (key, values) pairs inserted in the map
    pub fn iter_mut(&mut self) -> IterMut<K, Vec<V>> {
        self.map.iter_mut()
    }

    pub fn iter(&self) -> Iter<K, V> {
        Iter {
            iter: self.map.iter(),
        }
    }
}

impl<K: Eq + Hash + Clone, V> Extend<(K, V)> for ScopedMap<K, V> {
    fn extend<T>(&mut self, iter: T)
    where
        T: IntoIterator<Item = (K, V)>,
    {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

pub enum Entry<'a, K, V> {
    Vacant(VacantEntry<'a, K, V>),
    Occupied(OccupiedEntry<'a, K, V>),
}

pub struct VacantEntry<'a, K, V>(hash_map::VacantEntry<'a, K, Vec<V>>);
pub struct OccupiedEntry<'a, K, V>(hash_map::OccupiedEntry<'a, K, Vec<V>>);

impl<'a, K, V> VacantEntry<'a, K, V> {
    pub fn insert(self, value: V) -> &'a mut V {
        &mut self.0.insert(vec![value])[0]
    }
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
    pub fn key(&self) -> &K {
        self.0.key()
    }

    pub fn get(&self) -> &V {
        self.0.get().last().unwrap()
    }

    pub fn get_mut(&mut self) -> &mut V {
        self.0.get_mut().last_mut().unwrap()
    }

    pub fn into_mut(self) -> &'a mut V {
        self.0.into_mut().last_mut().unwrap()
    }

    pub fn insert(&mut self, value: V) {
        self.0.get_mut().push(value);
    }
}

pub struct Iter<'a, K, V>
where
    K: 'a,
    V: 'a,
{
    iter: hash_map::Iter<'a, K, Vec<V>>,
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: 'a,
    V: 'a,
{
    type Item = (&'a K, &'a V);

    fn next(&mut self) -> Option<(&'a K, &'a V)> {
        loop {
            match self.iter.next() {
                Some((k, vs)) => {
                    if let Some(v) = vs.last() {
                        return Some((k, v));
                    }
                }
                None => return None,
            }
        }
    }
}

pub struct ExitScopeIter<'a, K, V>
where
    K: 'a + Eq + Hash + Clone,
    V: 'a,
{
    map: &'a mut ScopedMap<K, V>,
    done: bool,
}

impl<'a, K, V> Drop for ExitScopeIter<'a, K, V>
where
    K: Eq + Hash + Clone,
{
    fn drop(&mut self) {
        for _ in self {}
    }
}

impl<'a, K, V> Iterator for ExitScopeIter<'a, K, V>
where
    K: Eq + Hash + Clone,
{
    type Item = (K, V);

    fn next(&mut self) -> Option<Self::Item> {
        if self.done {
            None
        } else {
            match self.map.scopes.pop() {
                Some(Some(key)) => {
                    let result = self.map.map.get_mut(&key).and_then(|x| x.pop());
                    self.done = result.is_none();
                    result.map(|value| (key, value))
                }
                _ => {
                    self.done = true;
                    None
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let mut map = ScopedMap::new();
        map.insert("a", 0);
        map.insert("b", 1);
        map.enter_scope();
        assert_eq!(map.get(&"a"), Some(&0));
        assert_eq!(map.get(&"b"), Some(&1));
        assert_eq!(map.get(&"c"), None);
        map.insert("a", 1);
        map.insert("c", 2);
        assert_eq!(map.get(&"a"), Some(&1));
        assert_eq!(map.get(&"c"), Some(&2));
        map.exit_scope();
        assert_eq!(map.get(&"a"), Some(&0));
        assert_eq!(map.get(&"c"), None);
    }
}
<|endoftext|>