<commit_before>pub mod application_command;
pub mod autocomplete;
pub mod message_component;
pub mod modal;
pub mod ping;

use application_command::ApplicationCommandInteraction;
use autocomplete::AutocompleteInteraction;
use bitflags::__impl_bitflags;
use message_component::MessageComponentInteraction;
use modal::ModalSubmitInteraction;
use ping::PingInteraction;
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::Value;

use super::prelude::*;
use crate::internal::prelude::*;

#[derive(Clone, Debug)]
pub enum Interaction {
    Ping(PingInteraction),
    ApplicationCommand(ApplicationCommandInteraction),
    MessageComponent(MessageComponentInteraction),
    Autocomplete(AutocompleteInteraction),
    ModalSubmit(ModalSubmitInteraction),
}

impl Interaction {
    /// Gets the interaction Id.
    pub fn id(&self) -> InteractionId {
        match self {
            Interaction::Ping(i) => i.id,
            Interaction::ApplicationCommand(i) => i.id,
            Interaction::MessageComponent(i) => i.id,
            Interaction::Autocomplete(i) => i.id,
            Interaction::ModalSubmit(i) => i.id,
        }
    }

    /// Gets the interaction type
    pub fn kind(&self) -> InteractionType {
        match self {
            Interaction::Ping(_) => InteractionType::Ping,
            Interaction::ApplicationCommand(_) => InteractionType::ApplicationCommand,
            Interaction::MessageComponent(_) => InteractionType::MessageComponent,
            Interaction::Autocomplete(_) => InteractionType::Autocomplete,
            Interaction::ModalSubmit(_) => InteractionType::ModalSubmit,
        }
    }

    /// Gets the interaction application Id
    pub fn application_id(&self) -> ApplicationId {
        match self {
            Interaction::Ping(i) => i.application_id,
            Interaction::ApplicationCommand(i) => i.application_id,
            Interaction::MessageComponent(i) => i.application_id,
            Interaction::Autocomplete(i) => i.application_id,
            Interaction::ModalSubmit(i) => i.application_id,
        }
    }

    /// Gets the interaction token.
    pub fn token(&self) -> &str {
        match self {
            Interaction::Ping(ref i) => i.token.as_str(),
            Interaction::ApplicationCommand(i) => i.token.as_str(),
            Interaction::MessageComponent(i) => i.token.as_str(),
            Interaction::Autocomplete(i) => i.token.as_str(),
            Interaction::ModalSubmit(i) => i.token.as_str(),
        }
    }

    /// Gets the invoked guild locale.
    pub fn guild_locale(&self) -> Option<&str> {
        match self {
            Interaction::Ping(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::ApplicationCommand(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::MessageComponent(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::Autocomplete(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::ModalSubmit(i) => i.guild_locale.as_ref().map(String::as_str),
        }
    }

    /// Converts this to a [`PingInteraction`]
    pub fn ping(self) -> Option<PingInteraction> {
        match self {
            Interaction::Ping(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    pub fn application_command(self) -> Option<ApplicationCommandInteraction> {
        match self {
            Interaction::ApplicationCommand(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`MessageComponentInteraction`]
    pub fn message_component(self) -> Option<MessageComponentInteraction> {
        match self {
            Interaction::MessageComponent(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`AutocompleteInteraction`]
    pub fn autocomplete(self) -> Option<AutocompleteInteraction> {
        match self {
            Interaction::Autocomplete(i) => Some(i),
            _ => None,
        }
    }
}

impl<'de> Deserialize<'de> for Interaction {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let map = JsonMap::deserialize(deserializer)?;

        let kind = map
            .get("type")
            .ok_or_else(|| DeError::custom("expected type"))
            .and_then(InteractionType::deserialize)
            .map_err(DeError::custom)?;

        match kind {
            InteractionType::Ping => serde_json::from_value::<PingInteraction>(Value::Object(map))
                .map(Interaction::Ping)
                .map_err(DeError::custom),
            InteractionType::ApplicationCommand => {
                serde_json::from_value::<ApplicationCommandInteraction>(Value::Object(map))
                    .map(Interaction::ApplicationCommand)
                    .map_err(DeError::custom)
            },
            InteractionType::MessageComponent => {
                serde_json::from_value::<MessageComponentInteraction>(Value::Object(map))
                    .map(Interaction::MessageComponent)
                    .map_err(DeError::custom)
            },
            InteractionType::Autocomplete => {
                serde_json::from_value::<AutocompleteInteraction>(Value::Object(map))
                    .map(Interaction::Autocomplete)
                    .map_err(DeError::custom)
            },
            InteractionType::ModalSubmit => {
                serde_json::from_value::<ModalSubmitInteraction>(Value::Object(map))
                    .map(Interaction::ModalSubmit)
                    .map_err(DeError::custom)
            },
            InteractionType::Unknown => Err(DeError::custom("Unknown interaction type")),
        }
    }
}

impl Serialize for Interaction {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Interaction::Ping(i) => PingInteraction::serialize(i, serializer),
            Interaction::ApplicationCommand(i) => {
                ApplicationCommandInteraction::serialize(i, serializer)
            },
            Interaction::MessageComponent(i) => {
                MessageComponentInteraction::serialize(i, serializer)
            },
            Interaction::Autocomplete(i) => AutocompleteInteraction::serialize(i, serializer),
            Interaction::ModalSubmit(i) => ModalSubmitInteraction::serialize(i, serializer),
        }
    }
}

/// The type of an Interaction.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionType {
    Ping = 1,
    ApplicationCommand = 2,
    MessageComponent = 3,
    Autocomplete = 4,
    ModalSubmit = 5,
    Unknown = !0,
}

enum_number!(InteractionType {
    Ping,
    MessageComponent,
    ApplicationCommand,
    Autocomplete,
    ModalSubmit
});

/// The flags for an interaction response.
#[derive(Clone)]
#[non_exhaustive]
pub struct InteractionApplicationCommandCallbackDataFlags {
    bits: u64,
}

__impl_bitflags! {
    InteractionApplicationCommandCallbackDataFlags: u64 {
        /// Interaction message will only be visible to sender and will
        /// be quickly deleted.
        EPHEMERAL = 1 << 6;
    }
}

impl<'de> Deserialize<'de> for InteractionApplicationCommandCallbackDataFlags {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?))
    }
}

impl Serialize for InteractionApplicationCommandCallbackDataFlags {
    fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u64(self.bits())
    }
}

/// Sent when a [`Message`] is a response to an [`Interaction`].
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MessageInteraction {
    /// The id of the interaction.
    pub id: InteractionId,
    /// The type of the interaction.
    #[serde(rename = "type")]
    pub kind: InteractionType,
    /// The name of the [`ApplicationCommand`].
    ///
    /// [`ApplicationCommand`]: crate::model::interactions::application_command::ApplicationCommand
    pub name: String,
    /// The user who invoked the interaction.
    pub user: User,
}

/// The available responses types for an interaction response.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionResponseType {
    Pong = 1,
    ChannelMessageWithSource = 4,
    DeferredChannelMessageWithSource = 5,
    DeferredUpdateMessage = 6,
    UpdateMessage = 7,
    Autocomplete = 8,
    Modal = 9,
}
<commit_msg>Add missing method for converting `Interaction` to `ModalSubmitInteraction` (#1762)<commit_after>pub mod application_command;
pub mod autocomplete;
pub mod message_component;
pub mod modal;
pub mod ping;

use application_command::ApplicationCommandInteraction;
use autocomplete::AutocompleteInteraction;
use bitflags::__impl_bitflags;
use message_component::MessageComponentInteraction;
use modal::ModalSubmitInteraction;
use ping::PingInteraction;
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::Value;

use super::prelude::*;
use crate::internal::prelude::*;

#[derive(Clone, Debug)]
pub enum Interaction {
    Ping(PingInteraction),
    ApplicationCommand(ApplicationCommandInteraction),
    MessageComponent(MessageComponentInteraction),
    Autocomplete(AutocompleteInteraction),
    ModalSubmit(ModalSubmitInteraction),
}

impl Interaction {
    /// Gets the interaction Id.
    pub fn id(&self) -> InteractionId {
        match self {
            Interaction::Ping(i) => i.id,
            Interaction::ApplicationCommand(i) => i.id,
            Interaction::MessageComponent(i) => i.id,
            Interaction::Autocomplete(i) => i.id,
            Interaction::ModalSubmit(i) => i.id,
        }
    }

    /// Gets the interaction type
    pub fn kind(&self) -> InteractionType {
        match self {
            Interaction::Ping(_) => InteractionType::Ping,
            Interaction::ApplicationCommand(_) => InteractionType::ApplicationCommand,
            Interaction::MessageComponent(_) => InteractionType::MessageComponent,
            Interaction::Autocomplete(_) => InteractionType::Autocomplete,
            Interaction::ModalSubmit(_) => InteractionType::ModalSubmit,
        }
    }

    /// Gets the interaction application Id
    pub fn application_id(&self) -> ApplicationId {
        match self {
            Interaction::Ping(i) => i.application_id,
            Interaction::ApplicationCommand(i) => i.application_id,
            Interaction::MessageComponent(i) => i.application_id,
            Interaction::Autocomplete(i) => i.application_id,
            Interaction::ModalSubmit(i) => i.application_id,
        }
    }

    /// Gets the interaction token.
    pub fn token(&self) -> &str {
        match self {
            Interaction::Ping(ref i) => i.token.as_str(),
            Interaction::ApplicationCommand(i) => i.token.as_str(),
            Interaction::MessageComponent(i) => i.token.as_str(),
            Interaction::Autocomplete(i) => i.token.as_str(),
            Interaction::ModalSubmit(i) => i.token.as_str(),
        }
    }

    /// Gets the invoked guild locale.
    pub fn guild_locale(&self) -> Option<&str> {
        match self {
            Interaction::Ping(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::ApplicationCommand(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::MessageComponent(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::Autocomplete(i) => i.guild_locale.as_ref().map(String::as_str),
            Interaction::ModalSubmit(i) => i.guild_locale.as_ref().map(String::as_str),
        }
    }

    /// Converts this to a [`PingInteraction`]
    pub fn ping(self) -> Option<PingInteraction> {
        match self {
            Interaction::Ping(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    pub fn application_command(self) -> Option<ApplicationCommandInteraction> {
        match self {
            Interaction::ApplicationCommand(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`MessageComponentInteraction`]
    pub fn message_component(self) -> Option<MessageComponentInteraction> {
        match self {
            Interaction::MessageComponent(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`AutocompleteInteraction`]
    pub fn autocomplete(self) -> Option<AutocompleteInteraction> {
        match self {
            Interaction::Autocomplete(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`ModalSubmitInteraction`]
    pub fn modal_submit(self) -> Option<ModalSubmitInteraction> {
        match self {
            Interaction::ModalSubmit(i) => Some(i),
            _ => None,
        }
    }
}

impl<'de> Deserialize<'de> for Interaction {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let map = JsonMap::deserialize(deserializer)?;

        let kind = map
            .get("type")
            .ok_or_else(|| DeError::custom("expected type"))
            .and_then(InteractionType::deserialize)
            .map_err(DeError::custom)?;

        match kind {
            InteractionType::Ping => serde_json::from_value::<PingInteraction>(Value::Object(map))
                .map(Interaction::Ping)
                .map_err(DeError::custom),
            InteractionType::ApplicationCommand => {
                serde_json::from_value::<ApplicationCommandInteraction>(Value::Object(map))
                    .map(Interaction::ApplicationCommand)
                    .map_err(DeError::custom)
            },
            InteractionType::MessageComponent => {
                serde_json::from_value::<MessageComponentInteraction>(Value::Object(map))
                    .map(Interaction::MessageComponent)
                    .map_err(DeError::custom)
            },
            InteractionType::Autocomplete => {
                serde_json::from_value::<AutocompleteInteraction>(Value::Object(map))
                    .map(Interaction::Autocomplete)
                    .map_err(DeError::custom)
            },
            InteractionType::ModalSubmit => {
                serde_json::from_value::<ModalSubmitInteraction>(Value::Object(map))
                    .map(Interaction::ModalSubmit)
                    .map_err(DeError::custom)
            },
            InteractionType::Unknown => Err(DeError::custom("Unknown interaction type")),
        }
    }
}

impl Serialize for Interaction {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Interaction::Ping(i) => PingInteraction::serialize(i, serializer),
            Interaction::ApplicationCommand(i) => {
                ApplicationCommandInteraction::serialize(i, serializer)
            },
            Interaction::MessageComponent(i) => {
                MessageComponentInteraction::serialize(i, serializer)
            },
            Interaction::Autocomplete(i) => AutocompleteInteraction::serialize(i, serializer),
            Interaction::ModalSubmit(i) => ModalSubmitInteraction::serialize(i, serializer),
        }
    }
}

/// The type of an Interaction.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionType {
    Ping = 1,
    ApplicationCommand = 2,
    MessageComponent = 3,
    Autocomplete = 4,
    ModalSubmit = 5,
    Unknown = !0,
}

enum_number!(InteractionType {
    Ping,
    MessageComponent,
    ApplicationCommand,
    Autocomplete,
    ModalSubmit
});

/// The flags for an interaction response.
#[derive(Clone)]
#[non_exhaustive]
pub struct InteractionApplicationCommandCallbackDataFlags {
    bits: u64,
}

__impl_bitflags! {
    InteractionApplicationCommandCallbackDataFlags: u64 {
        /// Interaction message will only be visible to sender and will
        /// be quickly deleted.
        EPHEMERAL = 1 << 6;
    }
}

impl<'de> Deserialize<'de> for InteractionApplicationCommandCallbackDataFlags {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?))
    }
}

impl Serialize for InteractionApplicationCommandCallbackDataFlags {
    fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u64(self.bits())
    }
}

/// Sent when a [`Message`] is a response to an [`Interaction`].
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MessageInteraction {
    /// The id of the interaction.
    pub id: InteractionId,
    /// The type of the interaction.
    #[serde(rename = "type")]
    pub kind: InteractionType,
    /// The name of the [`ApplicationCommand`].
    ///
    /// [`ApplicationCommand`]: crate::model::interactions::application_command::ApplicationCommand
    pub name: String,
    /// The user who invoked the interaction.
    pub user: User,
}

/// The available responses types for an interaction response.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionResponseType {
    Pong = 1,
    ChannelMessageWithSource = 4,
    DeferredChannelMessageWithSource = 5,
    DeferredUpdateMessage = 6,
    UpdateMessage = 7,
    Autocomplete = 8,
    Modal = 9,
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::SystemTime;
use std::collections::HashMap;

use diesel::pg::PgConnection;
use diesel::result::Error;
use diesel::*;
use diesel::{insert_into, update};

use serde::Serialize;

use crate::schema::worker_metadata;
use crate::backend;

#[derive(Insertable, Debug)]
#[table_name = "worker_metadata"]
/// Metadata collection for workers, updated by the dispatcher upon zmq transactions
pub struct NewWorkerMetadata {
  /// associated service for this worker metadata set
  pub service_id: i32,
  /// time of last ventilator dispatch to the service
  pub last_dispatched_task_id: i64,
  /// time of last sink job received from the service
  pub last_returned_task_id: Option<i64>,
  /// dispatch totals
  pub total_dispatched: i32,
  /// return totals
  pub total_returned: i32,
  /// first registered ventilator request for this worker, coincides with insertion in DB
  pub first_seen: SystemTime,
  /// first time seen in the current dispatcher session
  pub session_seen: Option<SystemTime>,
  /// time of last dispatched task
  pub time_last_dispatch: SystemTime,
  /// time of last returned job result
  pub time_last_return: Option<SystemTime>,
  /// identity of this worker, usually hostname:pid
  pub name: String,
}

#[derive(Identifiable, Queryable, Clone, Debug, Serialize)]
#[table_name = "worker_metadata"]
/// Metadata collection for workers, updated by the dispatcher upon zmq transactions
pub struct WorkerMetadata {
  /// task primary key, auto-incremented by postgresql
  pub id: i32,
  /// associated service for this worker metadata set
  pub service_id: i32,
  /// time of last ventilator dispatch to the service
  pub last_dispatched_task_id: i64,
  /// time of last sink job received from the service
  pub last_returned_task_id: Option<i64>,
  /// dispatch totals
  pub total_dispatched: i32,
  /// return totals
  pub total_returned: i32,
  /// first registered ventilator request for this worker, coincides with insertion in DB
  pub first_seen: SystemTime,
  /// first time seen in the current dispatcher session
  pub session_seen: Option<SystemTime>,
  /// time of last dispatched task
  pub time_last_dispatch: SystemTime,
  /// time of last returned job result
  pub time_last_return: Option<SystemTime>,
  /// identity of this worker, usually hostname:pid
  pub name: String,
}

impl From<WorkerMetadata> for HashMap<String, String> {
  fn from(worker: WorkerMetadata) -> HashMap<String, String> {
    let mut wh = HashMap::new();
    wh.insert("id".to_string(), worker.id.to_string());
    wh.insert("service_id".to_string(), worker.service_id.to_string());
    wh.insert(
      "last_dispatched_task_id".to_string(),
      worker.last_dispatched_task_id.to_string(),
    );
    wh.insert(
      "last_returned_task_id".to_string(),
      match worker.last_returned_task_id {
        Some(id) => id.to_string(),
        _ => String::new(),
      },
    );
    wh.insert(
      "total_dispatched".to_string(),
      worker.total_dispatched.to_string(),
    );
    wh.insert(
      "total_returned".to_string(),
      worker.total_returned.to_string(),
    );

    let mut fresh = false;
    wh.insert(
      "first_seen".to_string(),
      since_string(worker.first_seen, &mut fresh),
    );

    wh.insert(
      "session_seen".to_string(),
      match worker.session_seen {
        Some(session_seen) => since_string(session_seen, &mut fresh),
        None => String::new(),
      },
    );

    wh.insert(
      "time_last_dispatch".to_string(),
      since_string(worker.time_last_dispatch, &mut fresh),
    );
    wh.insert(
      "time_last_return".to_string(),
      match worker.time_last_return {
        Some(time_last_return) => since_string(time_last_return, &mut fresh),
        None => String::new(),
      },
    );
    wh.insert(
      "fresh".to_string(),
      if fresh { "fresh" } else { "stale" }.to_string(),
    );
    wh.insert("name".to_string(), worker.name.to_string());
    wh
  }
}

fn since_string(then: SystemTime, is_fresh: &mut bool) -> String {
  let now = SystemTime::now();
  let since_duration = now.duration_since(then).unwrap();
  let secs = since_duration.as_secs();
  if secs < 60 {
    *is_fresh = true;
    format!("{} seconds ago", secs)
  } else if secs < 3_600 {
    format!("{} minutes ago", secs / 60)
  } else if secs < 86_400 {
    format!("{} hours ago", secs / 3_600)
  } else {
    format!("{} days ago", secs / 86_400)
  }
}

impl WorkerMetadata {
  /// Update the metadata for a worker which was just dispatched to
  pub fn record_dispatched(
    name: String,
    service_id: i32,
    last_dispatched_task_id: i64,
    backend_address: String,
  ) -> Result<(), Error>
  {
    let now = SystemTime::now();
    let _ = thread::spawn(move || {
      let backend = backend::from_address(&backend_address);
      match WorkerMetadata::find_by_name(&name, service_id, &backend.connection) {
        Ok(data) => {
          // update with the appropriate fields.
          let session_seen = match data.session_seen {
            Some(time) => time,
            None => now,
          };
          use crate::schema::worker_metadata;
          update(&data)
            .set((
              worker_metadata::last_dispatched_task_id.eq(last_dispatched_task_id),
              worker_metadata::total_dispatched.eq(worker_metadata::total_dispatched + 1),
              worker_metadata::time_last_dispatch.eq(now),
              worker_metadata::session_seen.eq(Some(session_seen)),
            ))
            .execute(&backend.connection)
            .unwrap_or(0);
        },
        _ => {
          let data = NewWorkerMetadata {
            name,
            service_id,
            last_dispatched_task_id,
            last_returned_task_id: None,
            total_dispatched: 1,
            total_returned: 0,
            first_seen: now,
            session_seen: Some(now),
            time_last_dispatch: now,
            time_last_return: None,
          };
          insert_into(worker_metadata::table)
            .values(&data)
            .execute(&backend.connection)
            .unwrap_or(0);
        },
      }
    });
    Ok(())
  }
  /// Update the metadata for a worker which was just received from
  pub fn record_received(
    identity: String,
    service_id: i32,
    last_returned_task_id: i64,
    backend_address: String,
  ) -> Result<(), Error>
  {
    let now = SystemTime::now();
    let _ = thread::spawn(move || {
      let backend = backend::from_address(&backend_address);
      if let Ok(data) = WorkerMetadata::find_by_name(&identity, service_id, &backend.connection) {
        let session_seen = match data.session_seen {
          Some(time) => time,
          None => now,
        };
        use crate::schema::worker_metadata;
        update(&data)
          .set((
            worker_metadata::last_returned_task_id.eq(last_returned_task_id),
            worker_metadata::total_returned.eq(worker_metadata::total_returned + 1),
            worker_metadata::time_last_return.eq(now),
            worker_metadata::session_seen.eq(Some(session_seen)),
          ))
          .execute(&backend.connection)
          .unwrap_or(0);
      } else {
        println!(
          "-- Can't record worker metadata for unknown worker: {:?} {:?}",
          identity, service_id
        );
      }
    });
    Ok(())
  }

  /// Load worker metadata record by identity and service id
  pub fn find_by_name(
    identity: &str,
    sid: i32,
    connection: &PgConnection,
  ) -> Result<WorkerMetadata, Error>
  {
    use crate::schema::worker_metadata::{name, service_id};
    worker_metadata::table
      .filter(name.eq(identity))
      .filter(service_id.eq(sid))
      .get_result(connection)
  }
}
<commit_msg>drop redundant use<commit_after>use std::collections::HashMap;
use std::thread;
use std::time::SystemTime;

use diesel::pg::PgConnection;
use diesel::result::Error;
use diesel::*;
use diesel::{insert_into, update};

use serde::Serialize;

use crate::backend;
use crate::schema::worker_metadata;

#[derive(Insertable, Debug)]
#[table_name = "worker_metadata"]
/// Metadata collection for workers, updated by the dispatcher upon zmq transactions
pub struct NewWorkerMetadata {
  /// associated service for this worker metadata set
  pub service_id: i32,
  /// time of last ventilator dispatch to the service
  pub last_dispatched_task_id: i64,
  /// time of last sink job received from the service
  pub last_returned_task_id: Option<i64>,
  /// dispatch totals
  pub total_dispatched: i32,
  /// return totals
  pub total_returned: i32,
  /// first registered ventilator request for this worker, coincides with insertion in DB
  pub first_seen: SystemTime,
  /// first time seen in the current dispatcher session
  pub session_seen: Option<SystemTime>,
  /// time of last dispatched task
  pub time_last_dispatch: SystemTime,
  /// time of last returned job result
  pub time_last_return: Option<SystemTime>,
  /// identity of this worker, usually hostname:pid
  pub name: String,
}

#[derive(Identifiable, Queryable, Clone, Debug, Serialize)]
#[table_name = "worker_metadata"]
/// Metadata collection for workers, updated by the dispatcher upon zmq transactions
pub struct WorkerMetadata {
  /// task primary key, auto-incremented by postgresql
  pub id: i32,
  /// associated service for this worker metadata set
  pub service_id: i32,
  /// time of last ventilator dispatch to the service
  pub last_dispatched_task_id: i64,
  /// time of last sink job received from the service
  pub last_returned_task_id: Option<i64>,
  /// dispatch totals
  pub total_dispatched: i32,
  /// return totals
  pub total_returned: i32,
  /// first registered ventilator request for this worker, coincides with insertion in DB
  pub first_seen: SystemTime,
  /// first time seen in the current dispatcher session
  pub session_seen: Option<SystemTime>,
  /// time of last dispatched task
  pub time_last_dispatch: SystemTime,
  /// time of last returned job result
  pub time_last_return: Option<SystemTime>,
  /// identity of this worker, usually hostname:pid
  pub name: String,
}

impl From<WorkerMetadata> for HashMap<String, String> {
  fn from(worker: WorkerMetadata) -> HashMap<String, String> {
    let mut wh = HashMap::new();
    wh.insert("id".to_string(), worker.id.to_string());
    wh.insert("service_id".to_string(), worker.service_id.to_string());
    wh.insert(
      "last_dispatched_task_id".to_string(),
      worker.last_dispatched_task_id.to_string(),
    );
    wh.insert(
      "last_returned_task_id".to_string(),
      match worker.last_returned_task_id {
        Some(id) => id.to_string(),
        _ => String::new(),
      },
    );
    wh.insert(
      "total_dispatched".to_string(),
      worker.total_dispatched.to_string(),
    );
    wh.insert(
      "total_returned".to_string(),
      worker.total_returned.to_string(),
    );

    let mut fresh = false;
    wh.insert(
      "first_seen".to_string(),
      since_string(worker.first_seen, &mut fresh),
    );

    wh.insert(
      "session_seen".to_string(),
      match worker.session_seen {
        Some(session_seen) => since_string(session_seen, &mut fresh),
        None => String::new(),
      },
    );

    wh.insert(
      "time_last_dispatch".to_string(),
      since_string(worker.time_last_dispatch, &mut fresh),
    );
    wh.insert(
      "time_last_return".to_string(),
      match worker.time_last_return {
        Some(time_last_return) => since_string(time_last_return, &mut fresh),
        None => String::new(),
      },
    );
    wh.insert(
      "fresh".to_string(),
      if fresh { "fresh" } else { "stale" }.to_string(),
    );
    wh.insert("name".to_string(), worker.name.to_string());
    wh
  }
}

fn since_string(then: SystemTime, is_fresh: &mut bool) -> String {
  let now = SystemTime::now();
  let since_duration = now.duration_since(then).unwrap();
  let secs = since_duration.as_secs();
  if secs < 60 {
    *is_fresh = true;
    format!("{} seconds ago", secs)
  } else if secs < 3_600 {
    format!("{} minutes ago", secs / 60)
  } else if secs < 86_400 {
    format!("{} hours ago", secs / 3_600)
  } else {
    format!("{} days ago", secs / 86_400)
  }
}

impl WorkerMetadata {
  /// Update the metadata for a worker which was just dispatched to
  pub fn record_dispatched(
    name: String,
    service_id: i32,
    last_dispatched_task_id: i64,
    backend_address: String,
  ) -> Result<(), Error>
  {
    let now = SystemTime::now();
    let _ = thread::spawn(move || {
      let backend = backend::from_address(&backend_address);
      match WorkerMetadata::find_by_name(&name, service_id, &backend.connection) {
        Ok(data) => {
          // update with the appropriate fields.
          let session_seen = match data.session_seen {
            Some(time) => time,
            None => now,
          };
          update(&data)
            .set((
              worker_metadata::last_dispatched_task_id.eq(last_dispatched_task_id),
              worker_metadata::total_dispatched.eq(worker_metadata::total_dispatched + 1),
              worker_metadata::time_last_dispatch.eq(now),
              worker_metadata::session_seen.eq(Some(session_seen)),
            ))
            .execute(&backend.connection)
            .unwrap_or(0);
        },
        _ => {
          let data = NewWorkerMetadata {
            name,
            service_id,
            last_dispatched_task_id,
            last_returned_task_id: None,
            total_dispatched: 1,
            total_returned: 0,
            first_seen: now,
            session_seen: Some(now),
            time_last_dispatch: now,
            time_last_return: None,
          };
          insert_into(worker_metadata::table)
            .values(&data)
            .execute(&backend.connection)
            .unwrap_or(0);
        },
      }
    });
    Ok(())
  }
  /// Update the metadata for a worker which was just received from
  pub fn record_received(
    identity: String,
    service_id: i32,
    last_returned_task_id: i64,
    backend_address: String,
  ) -> Result<(), Error>
  {
    let now = SystemTime::now();
    let _ = thread::spawn(move || {
      let backend = backend::from_address(&backend_address);
      if let Ok(data) = WorkerMetadata::find_by_name(&identity, service_id, &backend.connection) {
        let session_seen = match data.session_seen {
          Some(time) => time,
          None => now,
        };
        use crate::schema::worker_metadata;
        update(&data)
          .set((
            worker_metadata::last_returned_task_id.eq(last_returned_task_id),
            worker_metadata::total_returned.eq(worker_metadata::total_returned + 1),
            worker_metadata::time_last_return.eq(now),
            worker_metadata::session_seen.eq(Some(session_seen)),
          ))
          .execute(&backend.connection)
          .unwrap_or(0);
      } else {
        println!(
          "-- Can't record worker metadata for unknown worker: {:?} {:?}",
          identity, service_id
        );
      }
    });
    Ok(())
  }

  /// Load worker metadata record by identity and service id
  pub fn find_by_name(
    identity: &str,
    sid: i32,
    connection: &PgConnection,
  ) -> Result<WorkerMetadata, Error>
  {
    use crate::schema::worker_metadata::{name, service_id};
    worker_metadata::table
      .filter(name.eq(identity))
      .filter(service_id.eq(sid))
      .get_result(connection)
  }
}
<|endoftext|>


<commit_before>use nn::{Module, ModuleStruct, ModDelegate, ModIntf, Parameter};
use autograd::Variable;
use nn::_functions::Conv2dFArgs;
use std::marker::PhantomData;
use nn::functional as F;

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv2dArgs<T: Default + Copy> {
    in_features: usize,
    out_features: usize,
    kernel_size: (usize, usize),
    #[builder(default="vec![1, 1]")]
    pub stride: Vec<u32>,
    #[builder(default="vec![0, 0]")]
    pub padding: Vec<u32>,
    #[builder(default="vec![1, 1]")]
    pub dilation: Vec<u32>,
    #[builder(default="1")]
    groups: u32,
    #[builder(default="true")]
    bias: bool,
    #[builder(default="PhantomData")]
    phantom: PhantomData<T>,
}

impl<T: Default + Copy> Conv2dArgsBuilder<T> {
    pub fn done(self) -> Conv2d<T> {
        let args = self.build().unwrap();
        Conv2d::new(args)
    }
}

#[derive(ModParse)]
pub struct Conv2d<T: Default + Copy> {
    delegate: Module<T>,
    weight: Parameter<T>,
    bias: Option<Parameter<T>>,
    #[ignore]
    args: Conv2dFArgs,
}

impl<T: Default + Copy> Conv2d<T> {
    pub fn build(in_features: usize,
                 out_features: usize,
                 kernel_size: (usize, usize))
                 -> Conv2dArgsBuilder<T> {
        Conv2dArgsBuilder::default()
            .in_features(in_features)
            .out_features(out_features)
            .kernel_size(kernel_size)
    }
    pub fn new(args: Conv2dArgs<T>) -> Conv2d<T> {
        let bias = if args.bias {
            Some(Parameter::new(vec![args.out_features]))
        } else {
            None
        };
        let fargs = Conv2dFArgs {
            kernel_size: vec![args.kernel_size.0, args.kernel_size.1],
            stride: args.stride.clone(),
            padding: args.padding.clone(),
            dilation: args.dilation.clone(),
            groups: args.groups,
        };
        Conv2d {
                delegate: Module::new(),
                weight: Parameter::new(vec![args.out_features, args.in_features]),
                bias: bias,
                args: fargs,
            }
            .init_module()
    }
}
impl_mod_delegate!(Conv2d);

impl<T: Default + Copy> ModIntf<T> for Conv2d<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T> {
        let mut bias = if let Some(ref mut biasp) = self.bias {
            Some(&mut biasp.v)
        } else {
            None
        };
        F::conv2d(input, &mut self.weight.v, bias, &mut self.args)
    }
}
<commit_msg>remove gratuitous mut<commit_after>use nn::{Module, ModuleStruct, ModDelegate, ModIntf, Parameter};
use autograd::Variable;
use nn::_functions::Conv2dFArgs;
use std::marker::PhantomData;
use nn::functional as F;

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv2dArgs<T: Default + Copy> {
    in_features: usize,
    out_features: usize,
    kernel_size: (usize, usize),
    #[builder(default="vec![1, 1]")]
    pub stride: Vec<u32>,
    #[builder(default="vec![0, 0]")]
    pub padding: Vec<u32>,
    #[builder(default="vec![1, 1]")]
    pub dilation: Vec<u32>,
    #[builder(default="1")]
    groups: u32,
    #[builder(default="true")]
    bias: bool,
    #[builder(default="PhantomData")]
    phantom: PhantomData<T>,
}

impl<T: Default + Copy> Conv2dArgsBuilder<T> {
    pub fn done(self) -> Conv2d<T> {
        let args = self.build().unwrap();
        Conv2d::new(args)
    }
}

#[derive(ModParse)]
pub struct Conv2d<T: Default + Copy> {
    delegate: Module<T>,
    weight: Parameter<T>,
    bias: Option<Parameter<T>>,
    #[ignore]
    args: Conv2dFArgs,
}

impl<T: Default + Copy> Conv2d<T> {
    pub fn build(in_features: usize,
                 out_features: usize,
                 kernel_size: (usize, usize))
                 -> Conv2dArgsBuilder<T> {
        Conv2dArgsBuilder::default()
            .in_features(in_features)
            .out_features(out_features)
            .kernel_size(kernel_size)
    }
    pub fn new(args: Conv2dArgs<T>) -> Conv2d<T> {
        let bias = if args.bias {
            Some(Parameter::new(vec![args.out_features]))
        } else {
            None
        };
        let fargs = Conv2dFArgs {
            kernel_size: vec![args.kernel_size.0, args.kernel_size.1],
            stride: args.stride.clone(),
            padding: args.padding.clone(),
            dilation: args.dilation.clone(),
            groups: args.groups,
        };
        Conv2d {
                delegate: Module::new(),
                weight: Parameter::new(vec![args.out_features, args.in_features]),
                bias: bias,
                args: fargs,
            }
            .init_module()
    }
}
impl_mod_delegate!(Conv2d);

impl<T: Default + Copy> ModIntf<T> for Conv2d<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T> {
        let bias = if let Some(ref mut biasp) = self.bias {
            Some(&mut biasp.v)
        } else {
            None
        };
        F::conv2d(input, &mut self.weight.v, bias, &mut self.args)
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Required for enabling benchmark tests.
#![feature(test)]

use anyhow::Context;
use log::Level;
use prost::Message;
use serde_derive::Deserialize;
use std::{
    collections::HashMap,
    fs,
    net::{Ipv6Addr, SocketAddr},
    sync::{Arc, RwLock},
    time::{Duration, Instant},
};
use structopt::StructOpt;

mod logger;
mod server;
use crate::{logger::Logger, server::create_and_start_server};

#[cfg(test)]
mod tests;
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Config {
    /// URL of a file to GET over HTTP containing key / value entries in protobuf binary format for
    /// lookup. If empty or not provided, no data is available for lookup.
    #[serde(default)]
    lookup_data_url: String,
    /// How often to refresh the lookup data. If not provided, data is only loaded once at startup.
    #[serde(with = "humantime_serde")]
    lookup_data_download_period: Option<Duration>,
}

/// Command line options for the Oak loader.
///
/// In general, when adding new configuration parameters, they should go in the `Config` struct
/// instead of here, and provided as part of the config TOML file by the developer, who would
/// normally bundle it with the Docker image of the Oak Functions Loader.
#[derive(StructOpt, Clone, Debug)]
#[structopt(about = "Oak Functions Loader")]
pub struct Opt {
    #[structopt(
        long,
        default_value = "8080",
        help = "Port number that the server listens on."
    )]
    http_listen_port: u16,
    #[structopt(
        long,
        help = "Path to a Wasm file to be loaded and executed per invocation. The Wasm module must export a function named `main`."
    )]
    wasm_path: String,
    #[structopt(
        long,
        help = "Path to a file containing configuration parameters in TOML format."
    )]
    config_path: String,
}

struct LookupData {
    lookup_data_url: String,
    entries: RwLock<HashMap<Vec<u8>, Vec<u8>>>,
    logger: Logger,
}

impl LookupData {
    /// Creates a new [`LookupData`] instance that can refresh its internal entries from the
    /// provided data file URL.
    ///
    /// Entries in the data file path must be consecutive binary encoded and length delimited
    /// protobuf messages according to the definition in `/oak_functions/proto/lookup_data.proto`.
    ///
    /// The returned instance is empty, and must be populated by calling the [`LookupData::refresh`]
    /// method at least once.
    fn new_empty(lookup_data_url: &str, logger: Logger) -> LookupData {
        LookupData {
            lookup_data_url: lookup_data_url.to_string(),
            entries: RwLock::new(HashMap::new()),
            logger,
        }
    }

    /// Refreshes the internal entries of this struct from the data file URL provided at
    /// construction time.
    ///
    /// If successful, entries are completely replaced (i.e. not merged).
    ///
    /// If there is any error while reading or parsing the data, an error is returned by this
    /// method, and existing entries are left untouched. The caller may retry the refresh operation
    /// at a future time.
    async fn refresh(&self) -> anyhow::Result<()> {
        // TODO(#1930): Avoid loading the entire file in memory for parsing.
        let client = hyper::Client::new();
        let res = client
            .get(
                self.lookup_data_url
                    .parse()
                    .context("could not parse lookup data URL")?,
            )
            .await
            .context("could not fetch lookup data")?;

        let start = Instant::now();
        let lookup_data_buf = hyper::body::to_bytes(res.into_body())
            .await
            .context("could not read lookup data response body")?;
        eprintln!("lookup data download time: {:?}", start.elapsed());

        let start = Instant::now();
        let entries = parse_lookup_entries(&mut lookup_data_buf.as_ref())
            .context("could not parse lookup data")?;

        self.logger.log_public(
            Level::Info,
            &format!("loaded {} entries of lookup data", entries.len()),
        );
        eprintln!("lookup data parsing time: {:?}", start.elapsed());

        // This block is here to emphasize and ensure that the write lock is only held for a very
        // short time.
        let start = Instant::now();
        {
            *self
                .entries
                .write()
                .expect("could not lock entries for write") = entries;
        }
        eprintln!(
            "lookup data write lock acquisition time: {:?}",
            start.elapsed()
        );

        Ok(())
    }

    /// Convenience getter for an individual entry that reduces lock contention by cloning the
    /// resulting value as quickly as possible and returning it instead of a reference.
    #[allow(dead_code)]
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.entries
            .read()
            .expect("could not lock entries for read")
            .get(key)
            .cloned()
    }

    #[allow(dead_code)]
    fn len(&self) -> usize {
        self.entries
            .read()
            .expect("could not lock entries for read")
            .len()
    }
}

fn parse_lookup_entries<B: bytes::Buf>(
    lookup_data_buffer: B,
) -> anyhow::Result<HashMap<Vec<u8>, Vec<u8>>> {
    let mut lookup_data_buffer = lookup_data_buffer;
    let mut entries = HashMap::new();
    while lookup_data_buffer.has_remaining() {
        let entry =
            oak_functions_abi::proto::Entry::decode_length_delimited(&mut lookup_data_buffer)
                .context("could not decode entry")?;
        entries.insert(entry.key, entry.value);
    }
    Ok(entries)
}

async fn background_refresh_lookup_data(lookup_data: &LookupData, period: Duration) {
    // Create an interval that starts after `period`, since the data was already refreshed
    // initially.
    let mut interval = tokio::time::interval_at(tokio::time::Instant::now() + period, period);
    loop {
        interval.tick().await;
        // If there is an error, we skip the current refresh and wait for the next tick.
        if let Err(err) = lookup_data.refresh().await {
            eprintln!("error refreshing lookup data: {}", err);
        }
    }
}

/// Main execution point for the Oak Functions Loader.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let opt = Opt::from_args();

    let config_file_bytes = fs::read(&opt.config_path)
        .with_context(|| format!("Couldn't read config file {}", &opt.config_path))?;
    let config: Config =
        toml::from_slice(&config_file_bytes).context("Couldn't parse config file")?;
    // Print the parsed config to STDERR regardless of whether the logger is initialized.
    eprintln!("parsed config file:\n{:#?}", config);

    // For now the server runs in the same thread, so `notify_sender` is not really needed.
    let (_notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();

    // TODO(#1971): Make maximum log level configurable.
    let logger = Logger::default();

    let wasm_module_bytes = fs::read(&opt.wasm_path)
        .with_context(|| format!("Couldn't read Wasm file {}", &opt.wasm_path))?;

    let lookup_data = Arc::new(LookupData::new_empty(
        &config.lookup_data_url,
        logger.clone(),
    ));
    if !config.lookup_data_url.is_empty() {
        // First load the lookup data upfront in a blocking fashion.
        // TODO(#1930): Retry the initial lookup a few times if it fails.
        lookup_data
            .refresh()
            .await
            .context("Couldn't perform initial load of lookup data")?;
        if let Some(lookup_data_download_period) = config.lookup_data_download_period {
            // Create background task to periodically refresh the lookup data.
            let lookup_data = lookup_data.clone();
            tokio::spawn(async move {
                background_refresh_lookup_data(&lookup_data, lookup_data_download_period).await
            });
        };
    }

    // TODO(#1930): Pass lookup data to the server instance.

    // Start HTTP server.
    let address = SocketAddr::from((Ipv6Addr::UNSPECIFIED, opt.http_listen_port));
    create_and_start_server(&address, &wasm_module_bytes, notify_receiver, logger).await
}
<commit_msg>Use new logger consistently (#1982)<commit_after>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Required for enabling benchmark tests.
#![feature(test)]

use anyhow::Context;
use log::Level;
use prost::Message;
use serde_derive::Deserialize;
use std::{
    collections::HashMap,
    fs,
    net::{Ipv6Addr, SocketAddr},
    sync::{Arc, RwLock},
    time::{Duration, Instant},
};
use structopt::StructOpt;

mod logger;
mod server;
use crate::{logger::Logger, server::create_and_start_server};

#[cfg(test)]
mod tests;
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Config {
    /// URL of a file to GET over HTTP containing key / value entries in protobuf binary format for
    /// lookup. If empty or not provided, no data is available for lookup.
    #[serde(default)]
    lookup_data_url: String,
    /// How often to refresh the lookup data. If not provided, data is only loaded once at startup.
    #[serde(with = "humantime_serde")]
    lookup_data_download_period: Option<Duration>,
}

/// Command line options for the Oak loader.
///
/// In general, when adding new configuration parameters, they should go in the `Config` struct
/// instead of here, and provided as part of the config TOML file by the developer, who would
/// normally bundle it with the Docker image of the Oak Functions Loader.
#[derive(StructOpt, Clone, Debug)]
#[structopt(about = "Oak Functions Loader")]
pub struct Opt {
    #[structopt(
        long,
        default_value = "8080",
        help = "Port number that the server listens on."
    )]
    http_listen_port: u16,
    #[structopt(
        long,
        help = "Path to a Wasm file to be loaded and executed per invocation. The Wasm module must export a function named `main`."
    )]
    wasm_path: String,
    #[structopt(
        long,
        help = "Path to a file containing configuration parameters in TOML format."
    )]
    config_path: String,
}

struct LookupData {
    lookup_data_url: String,
    entries: RwLock<HashMap<Vec<u8>, Vec<u8>>>,
    logger: Logger,
}

impl LookupData {
    /// Creates a new [`LookupData`] instance that can refresh its internal entries from the
    /// provided data file URL.
    ///
    /// Entries in the data file path must be consecutive binary encoded and length delimited
    /// protobuf messages according to the definition in `/oak_functions/proto/lookup_data.proto`.
    ///
    /// The returned instance is empty, and must be populated by calling the [`LookupData::refresh`]
    /// method at least once.
    fn new_empty(lookup_data_url: &str, logger: Logger) -> LookupData {
        LookupData {
            lookup_data_url: lookup_data_url.to_string(),
            entries: RwLock::new(HashMap::new()),
            logger,
        }
    }

    /// Refreshes the internal entries of this struct from the data file URL provided at
    /// construction time.
    ///
    /// If successful, entries are completely replaced (i.e. not merged).
    ///
    /// If there is any error while reading or parsing the data, an error is returned by this
    /// method, and existing entries are left untouched. The caller may retry the refresh operation
    /// at a future time.
    async fn refresh(&self) -> anyhow::Result<()> {
        // TODO(#1930): Avoid loading the entire file in memory for parsing.
        let client = hyper::Client::new();
        let res = client
            .get(
                self.lookup_data_url
                    .parse()
                    .context("could not parse lookup data URL")?,
            )
            .await
            .context("could not fetch lookup data")?;

        let start = Instant::now();
        let lookup_data_buf = hyper::body::to_bytes(res.into_body())
            .await
            .context("could not read lookup data response body")?;
        self.logger.log_public(
            Level::Debug,
            &format!("lookup data download time: {:?}", start.elapsed()),
        );

        let start = Instant::now();
        let entries = parse_lookup_entries(&mut lookup_data_buf.as_ref())
            .context("could not parse lookup data")?;

        self.logger.log_public(
            Level::Info,
            &format!("loaded {} entries of lookup data", entries.len()),
        );
        self.logger.log_public(
            Level::Debug,
            &format!("lookup data parsing time: {:?}", start.elapsed()),
        );

        // This block is here to emphasize and ensure that the write lock is only held for a very
        // short time.
        let start = Instant::now();
        {
            *self
                .entries
                .write()
                .expect("could not lock entries for write") = entries;
        }
        self.logger.log_public(
            Level::Debug,
            &format!(
                "lookup data write lock acquisition time: {:?}",
                start.elapsed()
            ),
        );

        Ok(())
    }

    /// Convenience getter for an individual entry that reduces lock contention by cloning the
    /// resulting value as quickly as possible and returning it instead of a reference.
    #[allow(dead_code)]
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.entries
            .read()
            .expect("could not lock entries for read")
            .get(key)
            .cloned()
    }

    #[allow(dead_code)]
    fn len(&self) -> usize {
        self.entries
            .read()
            .expect("could not lock entries for read")
            .len()
    }
}

fn parse_lookup_entries<B: bytes::Buf>(
    lookup_data_buffer: B,
) -> anyhow::Result<HashMap<Vec<u8>, Vec<u8>>> {
    let mut lookup_data_buffer = lookup_data_buffer;
    let mut entries = HashMap::new();
    while lookup_data_buffer.has_remaining() {
        let entry =
            oak_functions_abi::proto::Entry::decode_length_delimited(&mut lookup_data_buffer)
                .context("could not decode entry")?;
        entries.insert(entry.key, entry.value);
    }
    Ok(entries)
}

async fn background_refresh_lookup_data(lookup_data: &LookupData, period: Duration) {
    // Create an interval that starts after `period`, since the data was already refreshed
    // initially.
    let mut interval = tokio::time::interval_at(tokio::time::Instant::now() + period, period);
    loop {
        interval.tick().await;
        // If there is an error, we skip the current refresh and wait for the next tick.
        if let Err(err) = lookup_data.refresh().await {
            lookup_data.logger.log_public(
                Level::Error,
                &format!("error refreshing lookup data: {}", err),
            );
        }
    }
}

/// Main execution point for the Oak Functions Loader.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let opt = Opt::from_args();

    let config_file_bytes = fs::read(&opt.config_path)
        .with_context(|| format!("Couldn't read config file {}", &opt.config_path))?;
    let config: Config =
        toml::from_slice(&config_file_bytes).context("Couldn't parse config file")?;
    // Print the parsed config to STDERR regardless of whether the logger is initialized.

    // TODO(#1971): Make maximum log level configurable.
    let logger = Logger::default();

    logger.log_public(Level::Info, &format!("parsed config file:\n{:#?}", config));

    // For now the server runs in the same thread, so `notify_sender` is not really needed.
    let (_notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();

    let wasm_module_bytes = fs::read(&opt.wasm_path)
        .with_context(|| format!("Couldn't read Wasm file {}", &opt.wasm_path))?;

    let lookup_data = Arc::new(LookupData::new_empty(
        &config.lookup_data_url,
        logger.clone(),
    ));
    if !config.lookup_data_url.is_empty() {
        // First load the lookup data upfront in a blocking fashion.
        // TODO(#1930): Retry the initial lookup a few times if it fails.
        lookup_data
            .refresh()
            .await
            .context("Couldn't perform initial load of lookup data")?;
        if let Some(lookup_data_download_period) = config.lookup_data_download_period {
            // Create background task to periodically refresh the lookup data.
            let lookup_data = lookup_data.clone();
            tokio::spawn(async move {
                background_refresh_lookup_data(&lookup_data, lookup_data_download_period).await
            });
        };
    }

    // TODO(#1930): Pass lookup data to the server instance.

    // Start HTTP server.
    let address = SocketAddr::from((Ipv6Addr::UNSPECIFIED, opt.http_listen_port));
    create_and_start_server(&address, &wasm_module_bytes, notify_receiver, logger).await
}
<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader};
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use super::super::SharedStore;
use super::super::parsers::statsd::parse_metrics;

/// Listens on a TCP socket for StatsD messages.
pub struct StatsdTcpListener {
    store: SharedStore,
}

impl StatsdTcpListener {
    pub fn new(store: SharedStore) -> StatsdTcpListener {
        StatsdTcpListener {
            store: store,
        }
    }

    pub fn listen<A>(&self, addr: A)
        where A: ToSocketAddrs {
        let (send, recv) = channel();

        let listener = TcpListener::bind(addr).unwrap();
        thread::spawn(move || {
            StatsdTcpListener::accept_on_listener(listener, send)
        });

        for line in recv {
            self.handle_line(line)
        }
    }

    fn handle_line(&self, line: String) {
        let line_trimmed = line.trim_right();
        let result = parse_metrics(line_trimmed.as_bytes());

        match result {
            Ok(metrics) => {
                let metrics = metrics.iter().map(|m| m.to_standard_metric()).collect();
                self.store.record(metrics)
            },
            Err(err) => {
                println!("{:?}", err)
            },
        }
    }

    fn accept_on_listener(listener: TcpListener, send: Sender<String>) {
        for stream in listener.incoming() {
            match stream {
                Ok(stream) => {
                    // Clients have 30 seconds to send us data before we'll drop.
                    let _ = stream.set_read_timeout(Some(Duration::from_secs(30)));

                    let send = send.clone();

                    thread::spawn(move || {
                        StatsdTcpListener::handle_client(stream, send)
                    });
                },
                Err(e) => panic!("Failed to listen on TCP socket: {}", e),
            }
        }
    }

    fn handle_client(stream: TcpStream, send: Sender<String>) {
        let mut reader = BufReader::new(stream);

        loop {
            let mut line = String::new();

            match reader.read_line(&mut line) {
                Err(err) => {
                    println!("Error reading StatsD line: {:?}", err);
                    break
                },
                Ok(0) => {
                    // Close if there are no more bytes.
                    break
                },
                Ok(_) => {
                    send.send(line).unwrap()
                },
            }
        }
    }

}
<commit_msg>Add StatsD UDP server<commit_after>use std::io::{BufRead, BufReader};
use std::str;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use std::net::{
    TcpListener,
    TcpStream,
    ToSocketAddrs,
    UdpSocket
};

use super::super::SharedStore;
use super::super::parsers::statsd::parse_metrics;

/// Listens on a TCP socket for StatsD messages.
pub struct StatsdTcpListener {
    store: SharedStore,
}

impl StatsdTcpListener {
    pub fn new(store: SharedStore) -> StatsdTcpListener {
        StatsdTcpListener {
            store: store,
        }
    }

    pub fn listen<A>(&self, addr: A)
        where A: ToSocketAddrs {
        let (send, recv) = channel();

        let listener = TcpListener::bind(addr).unwrap();
        thread::spawn(move || {
            StatsdTcpListener::accept_on_listener(listener, send)
        });

        for line in recv {
            handle_line(&self.store, line)
        }
    }

    fn accept_on_listener(listener: TcpListener, send: Sender<String>) {
        for stream in listener.incoming() {
            match stream {
                Ok(stream) => {
                    // Clients have 30 seconds to send us data before we'll drop.
                    let _ = stream.set_read_timeout(Some(Duration::from_secs(30)));

                    let send = send.clone();

                    thread::spawn(move || {
                        StatsdTcpListener::handle_client(stream, send)
                    });
                },
                Err(e) => panic!("Failed to listen on TCP socket: {}", e),
            }
        }
    }

    fn handle_client(stream: TcpStream, send: Sender<String>) {
        let mut reader = BufReader::new(stream);

        loop {
            let mut line = String::new();

            match reader.read_line(&mut line) {
                Err(err) => {
                    println!("Error reading StatsD line: {:?}", err);
                    break
                },
                Ok(0) => {
                    // Close if there are no more bytes.
                    break
                },
                Ok(_) => {
                    send.send(line).unwrap()
                },
            }
        }
    } // fn handle_client
} // struct StatsdTcpListener

pub struct StatsdUdpListener {
    store: SharedStore,
}

impl StatsdUdpListener {
    pub fn new(store: SharedStore) -> StatsdUdpListener {
        StatsdUdpListener {
            store: store,
        }
    }

    pub fn listen<A>(&self, addr: A)
        where A: ToSocketAddrs {
        let (send, recv) = channel();

        let socket = UdpSocket::bind(addr).unwrap();

        thread::spawn(move || {
            let mut buf = [0; 1024];
            loop {
                let (bytes_read, _) = match socket.recv_from(&mut buf) {
                    Ok(pair) => pair,
                    Err(_) => return,
                };

                // Get a string from just the amount of bytes read.
                let message: &str = match str::from_utf8(&buf[..bytes_read]) {
                    Ok(s) => s,
                    Err(_) => return,
                };

                send.send(message.to_owned()).unwrap();
            }
        });

        for line in recv {
            handle_line(&self.store, line)
        }
    } // fn listen
} // impl StatsdUdpListener

fn handle_line(store: &SharedStore, line: String) {
    let line_trimmed = line.trim_right();
    let result = parse_metrics(line_trimmed.as_bytes());

    match result {
        Ok(metrics) => {
            let metrics = metrics.iter().map(|m| m.to_standard_metric()).collect();
            store.record(metrics)
        },
        Err(err) => {
            println!("{:?}", err)
        },
    }
}
<|endoftext|>


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

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];

const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
                                                 "avx512cd", "avx512dq", "avx512er",
                                                 "avx512f", "avx512ifma", "avx512pf",
                                                 "avx512vbmi", "avx512vl", "avx512vpopcntdq",
                                                 "bmi1", "bmi2", "fma", "fxsr",
                                                 "lzcnt", "mmx", "pclmulqdq",
                                                 "popcnt", "rdrand", "rdseed",
                                                 "sse", "sse2", "sse3", "sse4.1",
                                                 "sse4.2", "sse4a", "ssse3",
                                                 "tbm", "xsave", "xsavec",
                                                 "xsaveopt", "xsaves"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
                                                     "power8-altivec", "power9-altivec",
                                                     "power8-vector", "power9-vector",
                                                     "vsx"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa"];

pub fn to_llvm_feature(s: &str) -> &str {
    match s {
        "pclmulqdq" => "pclmul",
        "rdrand" => "rdrnd",
        "bmi1" => "bmi",
        s => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);
    target_feature_whitelist(sess)
        .iter()
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<commit_msg>Remove the v7 feature from AArch64<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon"];

const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
                                                 "avx512cd", "avx512dq", "avx512er",
                                                 "avx512f", "avx512ifma", "avx512pf",
                                                 "avx512vbmi", "avx512vl", "avx512vpopcntdq",
                                                 "bmi1", "bmi2", "fma", "fxsr",
                                                 "lzcnt", "mmx", "pclmulqdq",
                                                 "popcnt", "rdrand", "rdseed",
                                                 "sse", "sse2", "sse3", "sse4.1",
                                                 "sse4.2", "sse4a", "ssse3",
                                                 "tbm", "xsave", "xsavec",
                                                 "xsaveopt", "xsaves"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
                                                     "power8-altivec", "power9-altivec",
                                                     "power8-vector", "power9-vector",
                                                     "vsx"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa"];

pub fn to_llvm_feature(s: &str) -> &str {
    match s {
        "pclmulqdq" => "pclmul",
        "rdrand" => "rdrnd",
        "bmi1" => "bmi",
        s => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);
    target_feature_whitelist(sess)
        .iter()
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature)).collect()
}

pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
    match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    }
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<|endoftext|>


<commit_before>//! Simple binary loader.

use parser::binary::{Parser, ParserSource, Event};
pub use self::error::{Result, Error};
pub use self::generic::{GenericNode, OwnedAttribute};

pub mod error;
pub mod generic;
pub mod fbx7400;

/// FBX tree.
#[derive(Debug, Clone, PartialEq)]
pub enum Fbx {
    /// FBX 7.4 or later.
    Fbx7400(fbx7400::Fbx7400),
}

impl Fbx {
    /// Loads FBX structure from the given parser.
    pub fn load_from_parser<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let version = match parser.next_event()? {
            Event::StartFbx(header) => header.version,
            ev => {
                panic!("FBX binary parser should return `StartFbx` as the first event but got \
                        `{:?}`",
                       ev)
            },
        };
        match version {
            7400...7599 => fbx7400::Fbx7400::load_from_parser(version, parser).map(Fbx::Fbx7400),
            _ => {
                error!("Unsupported FBX version: {}", version);
                unimplemented!()
            },
        }
    }
}
<commit_msg>Improve documentation<commit_after>//! Simple binary loader.

use parser::binary::{Parser, ParserSource, Event};
pub use self::error::{Result, Error};
pub use self::generic::{GenericNode, OwnedAttribute};

pub mod error;
pub mod generic;
pub mod fbx7400;

/// FBX tree.
#[derive(Debug, Clone, PartialEq)]
pub enum Fbx {
    /// FBX 7.4 or later.
    Fbx7400(fbx7400::Fbx7400),
}

impl Fbx {
    /// Loads FBX structure from the given parser.
    ///
    /// # Panics
    /// Panics if the parser has already emitted some event (i.e. if the given parser didn't return
    /// the `StartFbx` first).
    pub fn load_from_parser<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Self> {
        let version = match parser.next_event()? {
            Event::StartFbx(header) => header.version,
            ev => {
                panic!("FBX binary parser should return `StartFbx` as the first event but got \
                        `{:?}`",
                       ev)
            },
        };
        match version {
            7400...7599 => fbx7400::Fbx7400::load_from_parser(version, parser).map(Fbx::Fbx7400),
            _ => {
                error!("Unsupported FBX version: {}", version);
                unimplemented!()
            },
        }
    }
}
<|endoftext|>


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

use prelude::*;
use core::fmt;

#[macro_use]
mod macros;

impl fmt::Display for super::UuidHyphenated {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidHyphenatedRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::UuidSimple {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidSimpleRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::UuidUrn {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidUrnRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::LowerHex for super::UuidHyphenated {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::LowerHex for super::UuidHyphenatedRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl fmt::LowerHex for super::UuidSimple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02x}", byte)?
        }

        Ok(())
    }
}

impl<'a> fmt::LowerHex for super::UuidSimpleRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02x}", byte)?
        }

        Ok(())
    }
}

impl fmt::LowerHex for super::UuidUrn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::LowerHex for super::UuidUrnRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl fmt::UpperHex for super::UuidHyphenated {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::UpperHex for super::UuidHyphenatedRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl fmt::UpperHex for super::UuidSimple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02X}", byte)?
        }

        Ok(())
    }
}

impl<'a> fmt::UpperHex for super::UuidSimpleRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02X}", byte)?
        }

        Ok(())
    }
}

impl fmt::UpperHex for super::UuidUrn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::UpperHex for super::UuidUrnRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl From<Uuid> for super::UuidHyphenated {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidHyphenated::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidHyphenatedRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidHyphenatedRef::from_uuid_ref(f)
    }
}

impl From<Uuid> for super::UuidSimple {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidSimple::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidSimpleRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidSimpleRef::from_uuid_ref(f)
    }
}

impl From<Uuid> for super::UuidUrn {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidUrn::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidUrnRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidUrnRef::from_uuid_ref(f)
    }
}
<commit_msg>fix fmt<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::fmt;
use prelude::*;

#[macro_use]
mod macros;

impl fmt::Display for super::UuidHyphenated {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidHyphenatedRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::UuidSimple {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidSimpleRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::UuidUrn {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<'a> fmt::Display for super::UuidUrnRef<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::LowerHex for super::UuidHyphenated {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::LowerHex for super::UuidHyphenatedRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl fmt::LowerHex for super::UuidSimple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02x}", byte)?
        }

        Ok(())
    }
}

impl<'a> fmt::LowerHex for super::UuidSimpleRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02x}", byte)?
        }

        Ok(())
    }
}

impl fmt::LowerHex for super::UuidUrn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::LowerHex for super::UuidUrnRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08x}-\
             {:04x}-\
             {:04x}-\
             {:02x}{:02x}-\
             {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            self.0.bytes
        )
    }
}

impl fmt::UpperHex for super::UuidHyphenated {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::UpperHex for super::UuidHyphenatedRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "{:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl fmt::UpperHex for super::UuidSimple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02X}", byte)?
        }

        Ok(())
    }
}

impl<'a> fmt::UpperHex for super::UuidSimpleRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for byte in &self.0.bytes {
            write!(f, "{:02X}", byte)?
        }

        Ok(())
    }
}

impl fmt::UpperHex for super::UuidUrn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl<'a> fmt::UpperHex for super::UuidUrnRef<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        hyphenated_write!(
            f,
            "urn:uuid:\
             {:08X}-\
             {:04X}-\
             {:04X}-\
             {:02X}{:02X}-\
             {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
            self.0.bytes
        )
    }
}

impl From<Uuid> for super::UuidHyphenated {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidHyphenated::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidHyphenatedRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidHyphenatedRef::from_uuid_ref(f)
    }
}

impl From<Uuid> for super::UuidSimple {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidSimple::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidSimpleRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidSimpleRef::from_uuid_ref(f)
    }
}

impl From<Uuid> for super::UuidUrn {
    #[inline]
    fn from(f: Uuid) -> Self {
        super::UuidUrn::from_uuid(f)
    }
}

impl<'a> From<&'a Uuid> for super::UuidUrnRef<'a> {
    #[inline]
    fn from(f: &'a Uuid) -> Self {
        super::UuidUrnRef::from_uuid_ref(f)
    }
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut visitor_count: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
	unsafe {
            	   visitor_count = visitor_count + 1;
	    }
        do spawn {
            let mut stream = stream;
            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            let mut index: int = 0;
	    let mut file_name = ~"";
	    for splitted in request_str.split(' ') {
	    	if(index == 1) {
			 file_name.push_str(splitted);
	     		 break;
		}
		index = index + 1;
	    }
	    let mut response = ~"";
	    let homepage = match file_name.len() {
	    	1 => true,
		_ => false
	    };
	    if(homepage) {
	    	response.push_str("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n");
            }
	    else {
	    	 let mut valid = true;
		 if(file_name.len() < 7) {
		 	valid = false;
		 }
		 if(valid) {
		 	let extension = file_name.slice_from(file_name.len() - 5).to_owned();
			let html_extension = ~".html";
			if(str::eq(&extension, &html_extension)) {
			     let file_name_abs = file_name.slice_from(1);
		             match File::open(&Path::new(file_name_abs.clone())) {
			     	   Some(html_file) => {
				              let mut html_file_mut = html_file;
					      let msg_bytes: ~[u8] = html_file_mut.read_to_end();
					      response.push_str(str::from_utf8(msg_bytes));
				   },
				   None => {
				        println("not found!");
				   	valid = false;
				   }
			     }
			}
			else {
			     valid = false;
			}
		 }
		 if(!valid) {
		 	    response.push_str("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>HTTP 403 Not Found</title>

HTTP 403 Error

Sorry, the page you requested does not exist. Please check the url.

                 \r\n");
		 }
	    }
            stream.write(response.as_bytes());
            println!("Connection terminates.");
	    unsafe {
	    	   println!("Visitor count: {:d}", visitor_count);
            }
	}
    }
}
<commit_msg>Problem solved! Done for ps1<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut visitor_count: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
	unsafe {
            	   visitor_count = visitor_count + 1;
	    }
        do spawn {
            let mut stream = stream;
            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            let mut index: int = 0;
	    let mut file_name = ~"";
	    for splitted in request_str.split(' ') {
	    	if(index == 1) {
			 file_name.push_str(splitted);
	     		 break;
		}
		index = index + 1;
	    }
	    let mut response = ~"";
	    let homepage = match file_name.len() {
	    	1 => true,
		_ => false
	    };
	    if(homepage) {
	    	response.push_str("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n");
            }
	    else {
	    	 let mut valid = true;
		 if(file_name.len() < 7) {
		 	valid = false;
		 }
		 if(valid) {
		 	let extension = file_name.slice_from(file_name.len() - 5).to_owned();
			let html_extension = ~".html";
			if(str::eq(&extension, &html_extension)) {
			     let file_name_abs = file_name.slice_from(1);
			     let path = Path::new(file_name_abs);
			     let opened_file: Option<File>;
			     if path.exists() && path.is_file() {
			     	opened_file = File::open(&path);
			     }
			     else {
			     	opened_file = None;
			     }
		             match opened_file {
			     	   Some(html_file) => {
				              let mut html_file_mut = html_file;
					      let msg_bytes: ~[u8] = html_file_mut.read_to_end();
					      response.push_str(str::from_utf8(msg_bytes));
				   },
				   None => {
				        println("not found!");
				   	valid = false;
				   }
			     }
			}
			else {
			     valid = false;
			}
		 }
		 if(!valid) {
		 	    response.push_str("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>HTTP 403 Not Found</title>

HTTP 403 Error

Sorry, the page you requested does not exist. Please check the url.

                 \r\n");
		 }
	    }
            stream.write(response.as_bytes());
            println!("Connection terminates.");
	    unsafe {
	    	   println!("Visitor count: {:d}", visitor_count);
            }
	}
    }
}
<|endoftext|>


<commit_before>use std::num;
use addressable::Addressable;

struct Area<ADDR> {
	base: ADDR,
	last: ADDR,
	handler: ~Addressable<ADDR>,
}

pub struct Memory<ADDR> {
	priv areas: ~[Area<ADDR>],
}

impl<ADDR> Memory<ADDR> {
	pub fn new () -> Memory<ADDR> {
		Memory { areas: ~[] }
	}

	pub fn add<T: Send+Addressable<ADDR>> (&mut self, base: ADDR, last: ADDR, handler: ~T) {
		self.areas.push(Area { base: base, last: last, handler: handler as ~Addressable<ADDR> });
	}
}

impl<ADDR: Int> Addressable<ADDR> for Memory<ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		for self.areas.rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				return area.handler.get(addr - area.base);
			}
		}
		fail!("memory: Read from unmapped memory area ($%x)", num::cast(addr));
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		for self.areas.mut_rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				area.handler.set(addr - area.base, data);
				return;
			}
		}
		fail!("memory: Write to unmapped memory area ($%x)", num::cast(addr));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use addressable::Addressable;
	use ram::Ram;

	#[test]
	fn test_read_write () {
		let mut m: Memory<u16> = Memory::new();
		let ram1: Ram<u16> = Ram::new_sized(0x0400);
		let ram2: Ram<u16> = Ram::new_sized(0x0400);
		m.add(0x0000, 0x0400, ~ram1);
		m.add(0x0200, 0x0600, ~ram2);
		m.set(0x0300, 123);
		assert_eq!(m.get(0x0300), 123);
	}
}
<commit_msg>Use borrowed pointers in memory mapper<commit_after>use std::num;
use addressable::Addressable;

struct Area<'self, ADDR> {
	base: ADDR,
	last: ADDR,
	handler: &'self mut Addressable<ADDR>,
}

pub struct Memory<'self, ADDR> {
	priv areas: ~[Area<'self, ADDR>],
}

impl<'self, ADDR> Memory<'self, ADDR> {
	pub fn new () -> Memory<ADDR> {
		Memory { areas: ~[] }
	}

	pub fn add<T: Send+Addressable<ADDR>> (&mut self, base: ADDR, last: ADDR, handler: &'self mut T) {
		self.areas.push(Area { base: base, last: last, handler: handler as &'self mut Addressable<ADDR> });
	}
}

impl<'self, ADDR: Int> Addressable<ADDR> for Memory<'self, ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		for self.areas.rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				return area.handler.get(addr - area.base);
			}
		}
		fail!("memory: Read from unmapped memory area ($%x)", num::cast(addr));
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		for self.areas.mut_rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				area.handler.set(addr - area.base, data);
				return;
			}
		}
		fail!("memory: Write to unmapped memory area ($%x)", num::cast(addr));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use addressable::Addressable;
	use ram::Ram;

	#[test]
	fn test_read_write () {
		let mut m: Memory<u16> = Memory::new();
		let mut ram1: Ram<u16> = Ram::new_sized(0x0400);
		let mut ram2: Ram<u16> = Ram::new_sized(0x0400);
		m.add(0x0000, 0x0400, &mut ram1);
		m.add(0x0200, 0x0600, &mut ram2);
		m.set(0x0300, 123);
		assert_eq!(m.get(0x0300), 123);
	}
}
<|endoftext|>