<commit_before>use crate::config::Config;
use crate::err::Result;
use crate::file::{FileType, SaveDir, SaveFile};
use anime::remote::{RemoteService, SeriesEntry, SeriesInfo, Status};
use chrono::{Local, NaiveDate};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;

#[derive(Debug, Deserialize, Serialize)]
pub struct EntryState {
    entry: SeriesEntry,
    needs_sync: bool,
}

impl EntryState {
    pub fn new(entry: SeriesEntry) -> EntryState {
        EntryState {
            entry,
            needs_sync: false,
        }
    }

    pub fn force_sync_changes_to_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if remote.is_offline() {
            self.save_with_id(self.entry.id, name.as_ref())?;
            return Ok(());
        }

        remote.update_list_entry(&self.entry)?;

        self.needs_sync = false;
        self.save_with_id(self.entry.id, name.as_ref())?;

        Ok(())
    }

    pub fn sync_changes_to_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if !self.needs_sync {
            return Ok(());
        }

        self.force_sync_changes_to_remote(remote, name)
    }

    pub fn force_sync_changes_from_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        let entry = match remote.get_list_entry(self.entry.id)? {
            Some(entry) => entry,
            None => return Ok(()),
        };

        self.entry = entry;
        self.save_with_id(self.entry.id, name.as_ref())?;

        Ok(())
    }

    pub fn sync_changes_from_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if self.needs_sync || remote.is_offline() {
            return Ok(());
        }

        self.force_sync_changes_from_remote(remote, name)
    }

    pub fn mark_as_dropped(&mut self, config: &Config) {
        if self.end_date().is_none()
            || (self.status() == Status::Rewatching && config.reset_dates_on_rewatch)
        {
            self.entry.end_date = Some(Local::today().naive_local());
        }

        self.entry.status = Status::Dropped;
        self.needs_sync = true;
    }

    pub fn mark_as_on_hold(&mut self) {
        self.entry.status = Status::OnHold;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn needs_sync(&self) -> bool {
        self.needs_sync
    }

    #[inline(always)]
    pub fn watched_eps(&self) -> u32 {
        self.entry.watched_eps
    }

    #[inline(always)]
    pub fn set_watched_eps(&mut self, watched_eps: u32) {
        self.entry.watched_eps = watched_eps;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn score(&self) -> Option<u8> {
        self.entry.score
    }

    #[inline(always)]
    pub fn set_score(&mut self, score: Option<u8>) {
        self.entry.score = score;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn status(&self) -> Status {
        self.entry.status
    }

    #[inline(always)]
    pub fn set_status(&mut self, status: Status) {
        self.entry.status = status;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn times_rewatched(&self) -> u32 {
        self.entry.times_rewatched
    }

    #[inline(always)]
    pub fn set_times_rewatched(&mut self, times_rewatched: u32) {
        self.entry.times_rewatched = times_rewatched;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn start_date(&self) -> Option<NaiveDate> {
        self.entry.start_date
    }

    #[inline(always)]
    pub fn set_start_date(&mut self, start_date: Option<NaiveDate>) {
        self.entry.start_date = start_date;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn end_date(&self) -> Option<NaiveDate> {
        self.entry.end_date
    }

    #[inline(always)]
    pub fn set_end_date(&mut self, end_date: Option<NaiveDate>) {
        self.entry.end_date = end_date;
        self.needs_sync = true;
    }
}

impl SaveFile for EntryState {
    fn filename() -> &'static str {
        "entry_state.mpack"
    }

    fn save_dir() -> SaveDir {
        SaveDir::LocalData
    }

    fn file_type() -> FileType {
        FileType::MessagePack
    }
}

impl From<u32> for EntryState {
    fn from(id: u32) -> EntryState {
        let entry = SeriesEntry::new(id);
        EntryState::new(entry)
    }
}

#[derive(Debug)]
pub struct SeriesTracker<'a> {
    pub info: Cow<'a, SeriesInfo>,
    pub state: EntryState,
    pub name: String,
}

impl<'a> SeriesTracker<'a> {
    pub fn init<I, S>(info: I, name: S) -> Result<SeriesTracker<'a>>
    where
        I: Into<Cow<'a, SeriesInfo>>,
        S: Into<String>,
    {
        let info = info.into();
        let name = name.into();

        let state = match EntryState::load_with_id(info.id, name.as_ref()) {
            Ok(state) => state,
            Err(ref err) if err.is_file_nonexistant() => EntryState::from(info.id),
            Err(err) => return Err(err),
        };

        Ok(SeriesTracker { info, state, name })
    }

    pub fn begin_watching<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;
        state.sync_changes_from_remote(remote, &self.name)?;

        let last_status = state.status();

        match last_status {
            Status::Watching | Status::Rewatching => {
                // There is an edge case where all episodes have been watched, but the status
                // is still set to watching / rewatching. Here we just start a rewatch
                if state.watched_eps() >= self.info.episodes {
                    state.set_status(Status::Rewatching);
                    state.set_watched_eps(0);

                    if last_status == Status::Rewatching {
                        state.set_times_rewatched(state.times_rewatched() + 1);
                    }
                }
            }
            Status::Completed => {
                state.set_status(Status::Rewatching);
                state.set_watched_eps(0);
            }
            Status::PlanToWatch => state.set_status(Status::Watching),
            Status::OnHold | Status::Dropped => {
                state.set_status(Status::Watching);
                state.set_watched_eps(0);
            }
        }

        if state.start_date().is_none()
            || (last_status == Status::Completed
                && state.status() == Status::Rewatching
                && config.reset_dates_on_rewatch)
        {
            state.set_start_date(Some(Local::today().naive_local()));
        }

        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }

    pub fn episode_completed<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;
        state.set_watched_eps(state.watched_eps() + 1);

        if state.watched_eps() >= self.info.episodes {
            return self.series_complete(remote, config);
        }

        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }

    pub fn series_complete<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;

        // A rewatch is typically only counted once the series is completed again
        if state.status() == Status::Rewatching {
            state.set_times_rewatched(state.times_rewatched() + 1);
        }

        if state.end_date().is_none()
            || (state.status() == Status::Rewatching && config.reset_dates_on_rewatch)
        {
            state.set_end_date(Some(Local::today().naive_local()));
        }

        state.set_status(Status::Completed);
        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }
}
<commit_msg>[anup] Use new SeriesEntry when a series isn't on the user's list<commit_after>use crate::config::Config;
use crate::err::Result;
use crate::file::{FileType, SaveDir, SaveFile};
use anime::remote::{RemoteService, SeriesEntry, SeriesInfo, Status};
use chrono::{Local, NaiveDate};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;

#[derive(Debug, Deserialize, Serialize)]
pub struct EntryState {
    entry: SeriesEntry,
    needs_sync: bool,
}

impl EntryState {
    pub fn new(entry: SeriesEntry) -> EntryState {
        EntryState {
            entry,
            needs_sync: false,
        }
    }

    pub fn force_sync_changes_to_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if remote.is_offline() {
            self.save_with_id(self.entry.id, name.as_ref())?;
            return Ok(());
        }

        remote.update_list_entry(&self.entry)?;

        self.needs_sync = false;
        self.save_with_id(self.entry.id, name.as_ref())?;

        Ok(())
    }

    pub fn sync_changes_to_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if !self.needs_sync {
            return Ok(());
        }

        self.force_sync_changes_to_remote(remote, name)
    }

    pub fn force_sync_changes_from_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        let entry = match remote.get_list_entry(self.entry.id)? {
            Some(entry) => entry,
            None => SeriesEntry::new(self.entry.id),
        };

        self.entry = entry;
        self.save_with_id(self.entry.id, name.as_ref())?;

        Ok(())
    }

    pub fn sync_changes_from_remote<R, S>(&mut self, remote: &R, name: S) -> Result<()>
    where
        R: RemoteService + ?Sized,
        S: AsRef<str>,
    {
        if self.needs_sync || remote.is_offline() {
            return Ok(());
        }

        self.force_sync_changes_from_remote(remote, name)
    }

    pub fn mark_as_dropped(&mut self, config: &Config) {
        if self.end_date().is_none()
            || (self.status() == Status::Rewatching && config.reset_dates_on_rewatch)
        {
            self.entry.end_date = Some(Local::today().naive_local());
        }

        self.entry.status = Status::Dropped;
        self.needs_sync = true;
    }

    pub fn mark_as_on_hold(&mut self) {
        self.entry.status = Status::OnHold;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn needs_sync(&self) -> bool {
        self.needs_sync
    }

    #[inline(always)]
    pub fn watched_eps(&self) -> u32 {
        self.entry.watched_eps
    }

    #[inline(always)]
    pub fn set_watched_eps(&mut self, watched_eps: u32) {
        self.entry.watched_eps = watched_eps;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn score(&self) -> Option<u8> {
        self.entry.score
    }

    #[inline(always)]
    pub fn set_score(&mut self, score: Option<u8>) {
        self.entry.score = score;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn status(&self) -> Status {
        self.entry.status
    }

    #[inline(always)]
    pub fn set_status(&mut self, status: Status) {
        self.entry.status = status;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn times_rewatched(&self) -> u32 {
        self.entry.times_rewatched
    }

    #[inline(always)]
    pub fn set_times_rewatched(&mut self, times_rewatched: u32) {
        self.entry.times_rewatched = times_rewatched;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn start_date(&self) -> Option<NaiveDate> {
        self.entry.start_date
    }

    #[inline(always)]
    pub fn set_start_date(&mut self, start_date: Option<NaiveDate>) {
        self.entry.start_date = start_date;
        self.needs_sync = true;
    }

    #[inline(always)]
    pub fn end_date(&self) -> Option<NaiveDate> {
        self.entry.end_date
    }

    #[inline(always)]
    pub fn set_end_date(&mut self, end_date: Option<NaiveDate>) {
        self.entry.end_date = end_date;
        self.needs_sync = true;
    }
}

impl SaveFile for EntryState {
    fn filename() -> &'static str {
        "entry_state.mpack"
    }

    fn save_dir() -> SaveDir {
        SaveDir::LocalData
    }

    fn file_type() -> FileType {
        FileType::MessagePack
    }
}

impl From<u32> for EntryState {
    fn from(id: u32) -> EntryState {
        let entry = SeriesEntry::new(id);
        EntryState::new(entry)
    }
}

#[derive(Debug)]
pub struct SeriesTracker<'a> {
    pub info: Cow<'a, SeriesInfo>,
    pub state: EntryState,
    pub name: String,
}

impl<'a> SeriesTracker<'a> {
    pub fn init<I, S>(info: I, name: S) -> Result<SeriesTracker<'a>>
    where
        I: Into<Cow<'a, SeriesInfo>>,
        S: Into<String>,
    {
        let info = info.into();
        let name = name.into();

        let state = match EntryState::load_with_id(info.id, name.as_ref()) {
            Ok(state) => state,
            Err(ref err) if err.is_file_nonexistant() => EntryState::from(info.id),
            Err(err) => return Err(err),
        };

        Ok(SeriesTracker { info, state, name })
    }

    pub fn begin_watching<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;
        state.sync_changes_from_remote(remote, &self.name)?;

        let last_status = state.status();

        match last_status {
            Status::Watching | Status::Rewatching => {
                // There is an edge case where all episodes have been watched, but the status
                // is still set to watching / rewatching. Here we just start a rewatch
                if state.watched_eps() >= self.info.episodes {
                    state.set_status(Status::Rewatching);
                    state.set_watched_eps(0);

                    if last_status == Status::Rewatching {
                        state.set_times_rewatched(state.times_rewatched() + 1);
                    }
                }
            }
            Status::Completed => {
                state.set_status(Status::Rewatching);
                state.set_watched_eps(0);
            }
            Status::PlanToWatch => state.set_status(Status::Watching),
            Status::OnHold | Status::Dropped => {
                state.set_status(Status::Watching);
                state.set_watched_eps(0);
            }
        }

        if state.start_date().is_none()
            || (last_status == Status::Completed
                && state.status() == Status::Rewatching
                && config.reset_dates_on_rewatch)
        {
            state.set_start_date(Some(Local::today().naive_local()));
        }

        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }

    pub fn episode_completed<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;
        state.set_watched_eps(state.watched_eps() + 1);

        if state.watched_eps() >= self.info.episodes {
            return self.series_complete(remote, config);
        }

        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }

    pub fn series_complete<R>(&mut self, remote: &R, config: &Config) -> Result<()>
    where
        R: RemoteService + ?Sized,
    {
        let state = &mut self.state;

        // A rewatch is typically only counted once the series is completed again
        if state.status() == Status::Rewatching {
            state.set_times_rewatched(state.times_rewatched() + 1);
        }

        if state.end_date().is_none()
            || (state.status() == Status::Rewatching && config.reset_dates_on_rewatch)
        {
            state.set_end_date(Some(Local::today().naive_local()));
        }

        state.set_status(Status::Completed);
        state.sync_changes_to_remote(remote, &self.name)?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>
use std::fmt;
use super::util;
use super::uuid::Uuid;
use super::secstr::SecStr;

#[derive(PartialEq)]
pub enum Field {
    Uuid(Vec<u8>),
    Group(Vec<u8>),
    Title(Vec<u8>),
    Username(Vec<u8>),
    Notes(Vec<u8>),
    Password(Vec<u8>),
    CreationTime(Vec<u8>),
    PasswordModificationTime(Vec<u8>),
    LastAccessTime(Vec<u8>),
    Url(Vec<u8>),
    Command(Vec<u8>),
    Email(Vec<u8>),
    Unknown(u8, Vec<u8>),
}

impl Field {
    pub fn from(typ: u8, val: Vec<u8>) -> Self {
        match typ {
            0x01 => Field::Uuid(val),
            0x02 => Field::Group(val),
            0x03 => Field::Title(val),
            0x04 => Field::Username(val),
            0x05 => Field::Notes(val),
            0x06 => Field::Password(val),
            0x07 => Field::CreationTime(val),
            0x08 => Field::PasswordModificationTime(val),
            0x09 => Field::LastAccessTime(val),
            0x0d => Field::Url(val),
            0x12 => Field::Command(val),
            0x14 => Field::Email(val),
            _ => Field::Unknown(typ, val),
        }
    }

    /// Return human readable field name
    pub fn name(&self) -> Option<&str> {
        match *self {
            Field::Uuid(_) => Some("uuid"),
            Field::Group(_) => Some("group"),
            Field::Title(_) => Some("title"),
            Field::Username(_) => Some("username"),
            Field::Notes(_) => Some("notes"),
            Field::Password(_) => Some("password"),
            Field::CreationTime(_) => Some("ctime"),
            Field::LastAccessTime(_) => Some("atime"),
            Field::Url(_) => Some("url"),
            Field::Email(_) => Some("email"),
            Field::Command(_) => Some("command"),
            _ => None,
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Field::Uuid(ref val) => {
                let uuid = Uuid::from_bytes(val.as_ref())
                    .unwrap_or(Uuid::nil())
                    .hyphenated().to_string();
                fmt.write_str(&uuid)
            }
            Field::Group(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Title(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Username(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Notes(_) => fmt.write_str("[Notes ...]"),
            Field::Password(_) => fmt.write_str("****"),
            Field::CreationTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::PasswordModificationTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::LastAccessTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::Url(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Email(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Command(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Unknown(typ, _) => write!(fmt, "Unknown Field({})", typ),
        }
    }
}

<commit_msg>Fix Display for Password/Notes Field variants<commit_after>
use std::fmt;
use super::util;
use super::uuid::Uuid;
use super::secstr::SecStr;

#[derive(PartialEq)]
pub enum Field {
    Uuid(Vec<u8>),
    Group(Vec<u8>),
    Title(Vec<u8>),
    Username(Vec<u8>),
    Notes(Vec<u8>),
    Password(Vec<u8>),
    CreationTime(Vec<u8>),
    PasswordModificationTime(Vec<u8>),
    LastAccessTime(Vec<u8>),
    Url(Vec<u8>),
    Command(Vec<u8>),
    Email(Vec<u8>),
    Unknown(u8, Vec<u8>),
}

impl Field {
    pub fn from(typ: u8, val: Vec<u8>) -> Self {
        match typ {
            0x01 => Field::Uuid(val),
            0x02 => Field::Group(val),
            0x03 => Field::Title(val),
            0x04 => Field::Username(val),
            0x05 => Field::Notes(val),
            0x06 => Field::Password(val),
            0x07 => Field::CreationTime(val),
            0x08 => Field::PasswordModificationTime(val),
            0x09 => Field::LastAccessTime(val),
            0x0d => Field::Url(val),
            0x12 => Field::Command(val),
            0x14 => Field::Email(val),
            _ => Field::Unknown(typ, val),
        }
    }

    /// Return human readable field name
    pub fn name(&self) -> Option<&str> {
        match *self {
            Field::Uuid(_) => Some("uuid"),
            Field::Group(_) => Some("group"),
            Field::Title(_) => Some("title"),
            Field::Username(_) => Some("username"),
            Field::Notes(_) => Some("notes"),
            Field::Password(_) => Some("password"),
            Field::CreationTime(_) => Some("ctime"),
            Field::LastAccessTime(_) => Some("atime"),
            Field::Url(_) => Some("url"),
            Field::Email(_) => Some("email"),
            Field::Command(_) => Some("command"),
            _ => None,
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Field::Uuid(ref val) => {
                let uuid = Uuid::from_bytes(val.as_ref())
                    .unwrap_or(Uuid::nil())
                    .hyphenated().to_string();
                fmt.write_str(&uuid)
            }
            Field::Group(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Title(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Username(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Notes(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Password(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::CreationTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::PasswordModificationTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::LastAccessTime(ref val) => {
                let ts = util::from_time_t(&val).unwrap_or(0);
                write!(fmt, "{}", ts)
            }
            Field::Url(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Email(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Command(ref v)  => {
                let s = String::from_utf8_lossy(v);
                fmt.write_str(&s)
            }
            Field::Unknown(typ, _) => write!(fmt, "Unknown Field({})", typ),
        }
    }
}

<|endoftext|>


<commit_before>use std::io;

use serde::de;
use flate2::read;

use raw;

use error::{Error, Result};

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_reader<'de, R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::Deserialize<'de>,
{
    let mut decoder = Decoder::new(src);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_gzip<'de, R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::Deserialize<'de>,
{
    let gzip = try!(read::GzDecoder::new(src));
    let mut decoder = Decoder::new(gzip);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_zlib<'de, R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::Deserialize<'de>,
{
    let mut zlib = read::ZlibDecoder::new(src);
    let mut decoder = Decoder::new(&mut zlib);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode objects from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub struct Decoder<R> {
    reader: R,
}

impl<R> Decoder<R> where R: io::Read {

    /// Create an NBT Decoder from a given `io::Read` source.
    pub fn new(src: R) -> Self {
        Decoder { reader: src }
    }
}

impl<'a, 'de, R: io::Read> de::Deserializer<'de> for &'a mut Decoder<R> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // The decoder cannot deserialize types by default. It can only handle
        // maps and structs.
        Err(Error::NoRootCompound)
    }

    fn deserialize_struct<V>(self, _name: &'static str,
                             _fields: &'static [&'static str], visitor: V)
                             -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // Ignore the header (if there is one).
        let (tag, _) = try!(raw::emit_next_header(&mut self.reader));

        match tag {
            0x0a => visitor.visit_map(MapDecoder::new(self)),
            _ => Err(Error::NoRootCompound)
        }
    }

    forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf
        unit seq tuple_struct tuple option enum identifier ignored_any
    }
}

/// Decoder for map-like types.
struct MapDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: Option<u8>,
}

impl<'a, R> MapDecoder<'a, R> where R: io::Read {

    fn new(outer: &'a mut Decoder<R>) -> Self {
        MapDecoder { outer: outer, tag: None }
    }
}

impl<'a, 'de, R: io::Read + 'a> de::MapAccess<'de> for MapDecoder<'a, R> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        let tag = try!(raw::read_bare_byte(&mut self.outer.reader));

        // NBT indicates the end of a compound type with a 0x00 tag.
        if tag == 0x00 {
            return Ok(None);
        }

        // Keep track of the tag so that we can decode the field correctly.
        self.tag = Some(tag as u8);

        // TODO: Enforce that keys must be String. This is a bit of a hack.
        let mut de = InnerDecoder { outer: self.outer, tag: 0x08 };

        Ok(Some(seed.deserialize(&mut de)?))
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: de::DeserializeSeed<'de>
    {
        let mut de = match self.tag {
            Some(tag) => InnerDecoder { outer: self.outer, tag: tag },
            None => unimplemented!(),
        };
        Ok(seed.deserialize(&mut de)?)
    }
}

/// Decoder for list-like types.
struct SeqDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
    length: i32,
    current: i32,
}

impl<'a, R> SeqDecoder<'a, R> where R: io::Read {

    fn list(outer: &'a mut Decoder<R>) -> Result<Self> {
        let tag = try!(raw::read_bare_byte(&mut outer.reader));
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: tag as u8, length: length,
                        current: 0 })
    }

    fn byte_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x01, length: length,
                        current: 0 })
    }

    fn int_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x03, length: length,
                        current: 0 })
    }
}

impl<'a, 'de, R: io::Read + 'a> de::SeqAccess<'de> for SeqDecoder<'a, R> {
    type Error = Error;

    fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        if self.current == self.length {
            return Ok(None);
        }

        let mut de = InnerDecoder { outer: self.outer, tag: self.tag };
        let value = try!(seed.deserialize(&mut de));

        self.current += 1;

        Ok(Some(value))
    }

    /// We always know the length of an NBT list in advance.
    fn size_hint(&self) -> Option<usize> {
        Some(self.length as usize)
    }
}

/// Private inner decoder, for decoding raw (i.e. non-Compound) types.
struct InnerDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
}

impl<'a, 'b: 'a, 'de, R: io::Read> de::Deserializer<'de> for &'b mut InnerDecoder<'a, R> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        let ref mut outer = self.outer;

        match self.tag {
            0x01 => visitor.visit_i8(raw::read_bare_byte(&mut outer.reader)?),
            0x02 => visitor.visit_i16(raw::read_bare_short(&mut outer.reader)?),
            0x03 => visitor.visit_i32(raw::read_bare_int(&mut outer.reader)?),
            0x04 => visitor.visit_i64(raw::read_bare_long(&mut outer.reader)?),
            0x05 => visitor.visit_f32(raw::read_bare_float(&mut outer.reader)?),
            0x06 => visitor.visit_f64(raw::read_bare_double(&mut outer.reader)?),
            0x07 => visitor.visit_seq(SeqDecoder::byte_array(outer)?),
            0x08 => visitor.visit_string(raw::read_bare_string(&mut outer.reader)?),
            0x09 => visitor.visit_seq(SeqDecoder::list(outer)?),
            0x0a => visitor.visit_map(MapDecoder::new(outer)),
            0x0b => visitor.visit_seq(SeqDecoder::int_array(outer)?),
            t => Err(Error::InvalidTypeId(t)),
        }
    }

    /// Deserialize bool values from a byte. Fail if that byte is not 0 or 1.
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        match self.tag {
            0x01 => {
                let ref mut reader = self.outer.reader;
                let value = try!(raw::read_bare_byte(reader));
                match value {
                    0 => visitor.visit_bool(false),
                    1 => visitor.visit_bool(true),
                    b => Err(Error::NonBooleanByte(b)),
                }
            },
            _ => Err(Error::TagMismatch(self.tag, 0x01)),
        }
    }

    /// Interpret missing values as None.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_some(self)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf seq
        map tuple_struct struct tuple enum identifier ignored_any
    }
}
<commit_msg>Updates from_reader() lifetimes to demand owned data.<commit_after>use std::io;

use serde::de;
use flate2::read;

use raw;

use error::{Error, Result};

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let mut decoder = Decoder::new(src);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_gzip<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let gzip = try!(read::GzDecoder::new(src));
    from_reader(gzip)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_zlib<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let zlib = read::ZlibDecoder::new(src);
    from_reader(zlib)
}

/// Decode objects from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub struct Decoder<R> {
    reader: R,
}

impl<R> Decoder<R> where R: io::Read {

    /// Create an NBT Decoder from a given `io::Read` source.
    pub fn new(src: R) -> Self {
        Decoder { reader: src }
    }
}

impl<'de: 'a, 'a, R: io::Read> de::Deserializer<'de> for &'a mut Decoder<R> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // The decoder cannot deserialize types by default. It can only handle
        // maps and structs.
        Err(Error::NoRootCompound)
    }

    fn deserialize_struct<V>(self, _name: &'static str,
                             _fields: &'static [&'static str], visitor: V)
                             -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // Ignore the header (if there is one).
        let (tag, _) = try!(raw::emit_next_header(&mut self.reader));

        match tag {
            0x0a => visitor.visit_map(MapDecoder::new(self)),
            _ => Err(Error::NoRootCompound)
        }
    }

    forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf
        unit seq tuple_struct tuple option enum identifier ignored_any
    }
}

/// Decoder for map-like types.
struct MapDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: Option<u8>,
}

impl<'a, R> MapDecoder<'a, R> where R: io::Read {

    fn new(outer: &'a mut Decoder<R>) -> Self {
        MapDecoder { outer: outer, tag: None }
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::MapAccess<'de> for MapDecoder<'a, R> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        let tag = try!(raw::read_bare_byte(&mut self.outer.reader));

        // NBT indicates the end of a compound type with a 0x00 tag.
        if tag == 0x00 {
            return Ok(None);
        }

        // Keep track of the tag so that we can decode the field correctly.
        self.tag = Some(tag as u8);

        // TODO: Enforce that keys must be String. This is a bit of a hack.
        let mut de = InnerDecoder { outer: self.outer, tag: 0x08 };

        Ok(Some(seed.deserialize(&mut de)?))
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: de::DeserializeSeed<'de>
    {
        let mut de = match self.tag {
            Some(tag) => InnerDecoder { outer: self.outer, tag: tag },
            None => unimplemented!(),
        };
        Ok(seed.deserialize(&mut de)?)
    }
}

/// Decoder for list-like types.
struct SeqDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
    length: i32,
    current: i32,
}

impl<'a, R> SeqDecoder<'a, R> where R: io::Read {

    fn list(outer: &'a mut Decoder<R>) -> Result<Self> {
        let tag = try!(raw::read_bare_byte(&mut outer.reader));
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: tag as u8, length: length,
                        current: 0 })
    }

    fn byte_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x01, length: length,
                        current: 0 })
    }

    fn int_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x03, length: length,
                        current: 0 })
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::SeqAccess<'de> for SeqDecoder<'a, R> {
    type Error = Error;

    fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        if self.current == self.length {
            return Ok(None);
        }

        let mut de = InnerDecoder { outer: self.outer, tag: self.tag };
        let value = try!(seed.deserialize(&mut de));

        self.current += 1;

        Ok(Some(value))
    }

    /// We always know the length of an NBT list in advance.
    fn size_hint(&self) -> Option<usize> {
        Some(self.length as usize)
    }
}

/// Private inner decoder, for decoding raw (i.e. non-Compound) types.
struct InnerDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
}

impl<'a, 'b: 'a, 'de, R: io::Read> de::Deserializer<'de> for &'b mut InnerDecoder<'a, R> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        let ref mut outer = self.outer;

        match self.tag {
            0x01 => visitor.visit_i8(raw::read_bare_byte(&mut outer.reader)?),
            0x02 => visitor.visit_i16(raw::read_bare_short(&mut outer.reader)?),
            0x03 => visitor.visit_i32(raw::read_bare_int(&mut outer.reader)?),
            0x04 => visitor.visit_i64(raw::read_bare_long(&mut outer.reader)?),
            0x05 => visitor.visit_f32(raw::read_bare_float(&mut outer.reader)?),
            0x06 => visitor.visit_f64(raw::read_bare_double(&mut outer.reader)?),
            0x07 => visitor.visit_seq(SeqDecoder::byte_array(outer)?),
            0x08 => visitor.visit_string(raw::read_bare_string(&mut outer.reader)?),
            0x09 => visitor.visit_seq(SeqDecoder::list(outer)?),
            0x0a => visitor.visit_map(MapDecoder::new(outer)),
            0x0b => visitor.visit_seq(SeqDecoder::int_array(outer)?),
            t => Err(Error::InvalidTypeId(t)),
        }
    }

    /// Deserialize bool values from a byte. Fail if that byte is not 0 or 1.
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        match self.tag {
            0x01 => {
                let ref mut reader = self.outer.reader;
                let value = try!(raw::read_bare_byte(reader));
                match value {
                    0 => visitor.visit_bool(false),
                    1 => visitor.visit_bool(true),
                    b => Err(Error::NonBooleanByte(b)),
                }
            },
            _ => Err(Error::TagMismatch(self.tag, 0x01)),
        }
    }

    /// Interpret missing values as None.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_some(self)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf seq
        map tuple_struct struct tuple enum identifier ignored_any
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;

use gleam::gl;
use std::collections::HashMap;
use webrender_traits::{BlobImageData, BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
use webrender_traits::{BlobImageResult, ImageStore, ColorF, ColorU, Epoch};
use webrender_traits::{DeviceUintSize, DeviceUintRect, LayoutPoint, LayoutRect, LayoutSize};
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat, ImageRendering, ImageKey, TileSize};
use webrender_traits::{PipelineId, RasterizedBlobImage, TransformStyle};

// This example shows how to implement a very basic BlobImageRenderer that can only render
// a checkerboard pattern.

// The deserialized command list internally used by this example is just a color.
type ImageRenderingCommands = ColorU;

// Serialize/deserialze the blob.
// Ror real usecases you should probably use serde rather than doing it by hand.

fn serialize_blob(color: ColorU) -> Vec<u8> {
    vec![color.r, color.g, color.b, color.a]
}

fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
    let mut iter = blob.iter();
    return match (iter.next(), iter.next(), iter.next(), iter.next()) {
        (Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(ColorU::new(r, g, b, a)),
        (Some(&a), None, None, None) => Ok(ColorU::new(a, a, a, a)),
        _ => Err(()),
    }
}

struct CheckerboardRenderer {
    // The deserialized drawing commands.
    image_cmds: HashMap<ImageKey, ImageRenderingCommands>,

    // The images rendered in the current frame (not kept here between frames)
    rendered_images: HashMap<BlobImageRequest, BlobImageResult>,
}

impl CheckerboardRenderer {
    fn new() -> Self {
        CheckerboardRenderer {
            image_cmds: HashMap::new(),
            rendered_images: HashMap::new(),
        }
    }
}

impl BlobImageRenderer for CheckerboardRenderer {
    fn add(&mut self, key: ImageKey, cmds: BlobImageData, _: Option<TileSize>) {
        self.image_cmds.insert(key, deserialize_blob(&cmds[..]).unwrap());
    }

    fn update(&mut self, key: ImageKey, cmds: BlobImageData) {
        // Here, updating is just replacing the current version of the commands with
        // the new one (no incremental updates)
        self.image_cmds.insert(key, deserialize_blob(&cmds[..]).unwrap());
    }

    fn delete(&mut self, key: ImageKey) {
        self.image_cmds.remove(&key);
    }

    fn request(&mut self,
               request: BlobImageRequest,
               descriptor: &BlobImageDescriptor,
               _dirty_rect: Option<DeviceUintRect>,
               _images: &ImageStore) {
        let color = self.image_cmds.get(&request.key).unwrap().clone();

        // Allocate storage for the result. Right now the resource cache expects the
        // tiles to have have no stride or offset.
        let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);

        // Generate a per-tile pattern to see it in the demo. For a real use case it would not
        // make sense for the rendered content to depend on its tile.
        let tile_checker = match request.tile {
            Some(tile) => (tile.x % 2 == 0) != (tile.y % 2 == 0),
            None => true,
        };

        for y in 0..descriptor.height {
            for x in 0..descriptor.width {
                // Apply the tile's offset. This is important: all drawing commands should be
                // translated by this offset to give correct results with tiled blob images.
                let x2 = x + descriptor.offset.x as u32;
                let y2 = y + descriptor.offset.y as u32;

                // Render a simple checkerboard pattern
                let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) { 1 } else { 0 };
                // ..nested in the per-tile cherkerboard pattern
                let tc = if tile_checker { 0 } else { (1 - checker) * 40 };

                match descriptor.format {
                    ImageFormat::RGBA8 => {
                        texels.push(color.b * checker + tc);
                        texels.push(color.g * checker + tc);
                        texels.push(color.r * checker + tc);
                        texels.push(color.a * checker + tc);
                    }
                    ImageFormat::A8 => {
                        texels.push(color.a * checker + tc);
                    }
                    _ => {
                        self.rendered_images.insert(request,
                            Err(BlobImageError::Other(format!(
                                "Usupported image format {:?}",
                                descriptor.format
                            )))
                        );
                        return;
                    }
                }
            }
        }

        self.rendered_images.insert(request, Ok(RasterizedBlobImage {
            data: texels,
            width: descriptor.width,
            height: descriptor.height,
        }));
    }

    fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
        self.rendered_images.remove(&request).unwrap_or(Err(BlobImageError::InvalidKey))
    }
}

fn main() {
    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample (BlobImageRenderer)")
                .with_multitouch()
                .with_gl(glutin::GlRequest::GlThenGles {
                    opengl_version: (3, 2),
                    opengles_version: (3, 0)
                })
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
    }

    let gl = match gl::GlType::default() {
        gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
        gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));

    let (width, height) = window.get_inner_size_pixels().unwrap();

    let opts = webrender::RendererOptions {
        debug: true,
        blob_image_renderer: Some(Box::new(CheckerboardRenderer::new())),
        device_pixel_ratio: window.hidpi_factor(),
        .. Default::default()
    };

    let size = DeviceUintSize::new(width, height);
    let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
    let api = sender.create_api();

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.2, 0.2, 0.2, 1.0);

    let blob_img1 = api.generate_image_key();
    api.add_image(
        blob_img1,
        ImageDescriptor::new(500, 500, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(serialize_blob(ColorU::new(50, 50, 150, 255))),
        Some(128),
    );

    let blob_img2 = api.generate_image_key();
    api.add_image(
        blob_img2,
        ImageDescriptor::new(200, 200, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(serialize_blob(ColorU::new(50, 150, 50, 255))),
        None,
    );

    let pipeline_id = PipelineId(0, 0);
    let layout_size = LayoutSize::new(width as f32, height as f32);
    let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);

    let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  None,
                                  TransformStyle::Flat,
                                  None,
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());

    let clip = builder.push_clip_region(&bounds, vec![], None);
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(30.0, 30.0), LayoutSize::new(500.0, 500.0)),
        clip,
        LayoutSize::new(500.0, 500.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        blob_img1,
    );

    let clip = builder.push_clip_region(&bounds, vec![], None);
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(600.0, 60.0), LayoutSize::new(200.0, 200.0)),
        clip,
        LayoutSize::new(200.0, 200.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        blob_img2,
    );

    builder.pop_stacking_context();

    api.set_display_list(
        Some(root_background_color),
        epoch,
        LayoutSize::new(width as f32, height as f32),
        builder.finalize(),
        true);
    api.set_root_pipeline(pipeline_id);
    api.generate_frame(None);

    'outer: for event in window.wait_events() {
        let mut events = Vec::new();
        events.push(event);

        for event in window.poll_events() {
            events.push(event);
        }

        for event in events {
            match event {
                glutin::Event::Closed |
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::P)) => {
                    let enable_profiler = !renderer.get_profiler_enabled();
                    renderer.set_profiler_enabled(enable_profiler);
                    api.generate_frame(None);
                }
                _ => ()
            }
        }

        renderer.update();
        renderer.render(DeviceUintSize::new(width, height));
        window.swap_buffers().ok();
    }
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }
}
<commit_msg>Auto merge of #1179 - nical:blob-threads, r=kvark<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;
extern crate rayon;

use gleam::gl;
use rayon::ThreadPool;
use rayon::Configuration as ThreadPoolConfig;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use webrender_traits::{BlobImageData, BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
use webrender_traits::{BlobImageResult, TileOffset, ImageStore, ColorF, ColorU, Epoch};
use webrender_traits::{DeviceUintSize, DeviceUintRect, LayoutPoint, LayoutRect, LayoutSize};
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat, ImageRendering, ImageKey, TileSize};
use webrender_traits::{PipelineId, RasterizedBlobImage, TransformStyle};

// This example shows how to implement a very basic BlobImageRenderer that can only render
// a checkerboard pattern.

// The deserialized command list internally used by this example is just a color.
type ImageRenderingCommands = ColorU;

// Serialize/deserialze the blob.
// Ror real usecases you should probably use serde rather than doing it by hand.

fn serialize_blob(color: ColorU) -> Vec<u8> {
    vec![color.r, color.g, color.b, color.a]
}

fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
    let mut iter = blob.iter();
    return match (iter.next(), iter.next(), iter.next(), iter.next()) {
        (Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(ColorU::new(r, g, b, a)),
        (Some(&a), None, None, None) => Ok(ColorU::new(a, a, a, a)),
        _ => Err(()),
    }
}

// This is the function that applies the deserialized drawing commands and generates
// actual image data.
fn render_blob(
    commands: Arc<ImageRenderingCommands>,
    descriptor: &BlobImageDescriptor,
    tile: Option<TileOffset>,
) -> BlobImageResult {
    let color = *commands;

    // Allocate storage for the result. Right now the resource cache expects the
    // tiles to have have no stride or offset.
    let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);

    // Generate a per-tile pattern to see it in the demo. For a real use case it would not
    // make sense for the rendered content to depend on its tile.
    let tile_checker = match tile {
        Some(tile) => (tile.x % 2 == 0) != (tile.y % 2 == 0),
        None => true,
    };

    for y in 0..descriptor.height {
        for x in 0..descriptor.width {
            // Apply the tile's offset. This is important: all drawing commands should be
            // translated by this offset to give correct results with tiled blob images.
            let x2 = x + descriptor.offset.x as u32;
            let y2 = y + descriptor.offset.y as u32;

            // Render a simple checkerboard pattern
            let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) { 1 } else { 0 };
            // ..nested in the per-tile cherkerboard pattern
            let tc = if tile_checker { 0 } else { (1 - checker) * 40 };

            match descriptor.format {
                ImageFormat::RGBA8 => {
                    texels.push(color.b * checker + tc);
                    texels.push(color.g * checker + tc);
                    texels.push(color.r * checker + tc);
                    texels.push(color.a * checker + tc);
                }
                ImageFormat::A8 => {
                    texels.push(color.a * checker + tc);
                }
                _ => {
                    return Err(BlobImageError::Other(format!(
                        "Usupported image format {:?}",
                        descriptor.format
                    )));
                }
            }
        }
    }

    Ok(RasterizedBlobImage {
        data: texels,
        width: descriptor.width,
        height: descriptor.height,
    })
}

struct CheckerboardRenderer {
    // We are going to defer the rendering work to worker threads.
    // Using a pre-built Arc<ThreadPool> rather than creating our own threads
    // makes it possible to share the same thread pool as the glyph renderer (if we
    // want to).
    workers: Arc<ThreadPool>,

    // the workers will use an mpsc channel to communicate the result.
    tx: Sender<(BlobImageRequest, BlobImageResult)>,
    rx: Receiver<(BlobImageRequest, BlobImageResult)>,

    // The deserialized drawing commands.
    // In this example we store them in Arcs. This isn't necessary since in this simplified
    // case the command list is a simple 32 bits value and would be cheap to clone before sending
    // to the workers. But in a more realistic scenario the commands would typically be bigger
    // and more expensive to clone, so let's pretend it is also the case here.
    image_cmds: HashMap<ImageKey, Arc<ImageRenderingCommands>>,

    // The images rendered in the current frame (not kept here between frames).
    rendered_images: HashMap<BlobImageRequest, Option<BlobImageResult>>,
}

impl CheckerboardRenderer {
    fn new(workers: Arc<ThreadPool>) -> Self {
        let (tx, rx) = channel();
        CheckerboardRenderer {
            image_cmds: HashMap::new(),
            rendered_images: HashMap::new(),
            workers: workers,
            tx: tx,
            rx: rx,
        }
    }
}

impl BlobImageRenderer for CheckerboardRenderer {
    fn add(&mut self, key: ImageKey, cmds: BlobImageData, _: Option<TileSize>) {
        self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
    }

    fn update(&mut self, key: ImageKey, cmds: BlobImageData) {
        // Here, updating is just replacing the current version of the commands with
        // the new one (no incremental updates).
        self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
    }

    fn delete(&mut self, key: ImageKey) {
        self.image_cmds.remove(&key);
    }

    fn request(&mut self,
               request: BlobImageRequest,
               descriptor: &BlobImageDescriptor,
               _dirty_rect: Option<DeviceUintRect>,
               _images: &ImageStore) {
        // This method is where we kick off our rendering jobs.
        // It should avoid doing work on the calling thread as much as possible.
        // In this example we will use the thread pool to render individual tiles.

        // Gather the input data to send to a worker thread.
        let cmds = Arc::clone(&self.image_cmds.get(&request.key).unwrap());
        let tx = self.tx.clone();
        let descriptor = descriptor.clone();

        self.workers.spawn_async(move || {
            let result = render_blob(cmds, &descriptor, request.tile);
            tx.send((request, result)).unwrap();
        });

        // Add None in the map of rendered images. This makes it possible to differentiate
        // between commands that aren't finished yet (entry in the map is equal to None) and
        // keys that have never been requested (entry not in the map), which would cause deadlocks
        // if we were to block upon receing their result in resolve!
        self.rendered_images.insert(request, None);
    }

    fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
        // In this method we wait until the work is complete on the worker threads and
        // gather the results.

        // First look at whether we have already received the rendered image
        // that we are looking for.
        match self.rendered_images.entry(request) {
            Entry::Vacant(_) => {
                return Err(BlobImageError::InvalidKey);
            }
            Entry::Occupied(entry) => {
                // None means we haven't yet received the result.
                if entry.get().is_some() {
                    let result = entry.remove();
                    return result.unwrap();
                }
            }
        }

        // We haven't received it yet, pull from the channel until we receive it.
        while let Ok((req, result)) = self.rx.recv() {
            if req == request {
                // There it is!
                return result
            }
            self.rendered_images.insert(req, Some(result));
        }

        // If we break out of the loop above it means the channel closed unexpectedly.
        Err(BlobImageError::Other("Channel closed".into()))
    }
}

fn main() {
    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample (BlobImageRenderer)")
                .with_multitouch()
                .with_gl(glutin::GlRequest::GlThenGles {
                    opengl_version: (3, 2),
                    opengles_version: (3, 0)
                })
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
    }

    let gl = match gl::GlType::default() {
        gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
        gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));

    let (width, height) = window.get_inner_size_pixels().unwrap();

    let worker_config = ThreadPoolConfig::new().thread_name(|idx|{
        format!("WebRender:Worker#{}", idx)
    });

    let workers = Arc::new(ThreadPool::new(worker_config).unwrap());

    let opts = webrender::RendererOptions {
        debug: true,
        workers: Some(Arc::clone(&workers)),
        // Register our blob renderer, so that WebRender integrates it in the resource cache..
        // Share the same pool of worker threads between WebRender and our blob renderer.
        blob_image_renderer: Some(Box::new(CheckerboardRenderer::new(Arc::clone(&workers)))),
        device_pixel_ratio: window.hidpi_factor(),
        .. Default::default()
    };

    let size = DeviceUintSize::new(width, height);
    let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
    let api = sender.create_api();

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.2, 0.2, 0.2, 1.0);

    let blob_img1 = api.generate_image_key();
    api.add_image(
        blob_img1,
        ImageDescriptor::new(500, 500, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(serialize_blob(ColorU::new(50, 50, 150, 255))),
        Some(128),
    );

    let blob_img2 = api.generate_image_key();
    api.add_image(
        blob_img2,
        ImageDescriptor::new(200, 200, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(serialize_blob(ColorU::new(50, 150, 50, 255))),
        None,
    );

    let pipeline_id = PipelineId(0, 0);
    let layout_size = LayoutSize::new(width as f32, height as f32);
    let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);

    let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  None,
                                  TransformStyle::Flat,
                                  None,
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());

    let clip = builder.push_clip_region(&bounds, vec![], None);
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(30.0, 30.0), LayoutSize::new(500.0, 500.0)),
        clip,
        LayoutSize::new(500.0, 500.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        blob_img1,
    );

    let clip = builder.push_clip_region(&bounds, vec![], None);
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(600.0, 60.0), LayoutSize::new(200.0, 200.0)),
        clip,
        LayoutSize::new(200.0, 200.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        blob_img2,
    );

    builder.pop_stacking_context();

    api.set_display_list(
        Some(root_background_color),
        epoch,
        LayoutSize::new(width as f32, height as f32),
        builder.finalize(),
        true);
    api.set_root_pipeline(pipeline_id);
    api.generate_frame(None);

    'outer: for event in window.wait_events() {
        let mut events = Vec::new();
        events.push(event);

        for event in window.poll_events() {
            events.push(event);
        }

        for event in events {
            match event {
                glutin::Event::Closed |
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::P)) => {
                    let enable_profiler = !renderer.get_profiler_enabled();
                    renderer.set_profiler_enabled(enable_profiler);
                    api.generate_frame(None);
                }
                _ => ()
            }
        }

        renderer.update();
        renderer.render(DeviceUintSize::new(width, height));
        window.swap_buffers().ok();
    }
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }
}
<|endoftext|>


<commit_before>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
extern crate dotenv;

use self::dotenv::dotenv;

use self::websocket::message::OwnedMessage;
use self::websocket::server::{WsServer, InvalidConnection};
use self::websocket::async::{Server, MessageCodec};
use self::websocket::client::async::Framed;
use self::websocket::server::NoTlsAcceptor;

use self::tokio_core::reactor::{Handle, Remote, Core};
use self::tokio_core::net::{TcpStream, TcpListener};

use self::futures::{Future, Sink, Stream};
use self::futures::sync::mpsc;
use self::futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::rc::Rc;
use std::fmt::Debug;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

use model::client::ClientState;
use util::read_env_var;

pub type Id = u32;

type SinkContent = Framed<TcpStream, MessageCodec<OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;

#[derive(Clone)]
pub struct ConnectionData {
    pub ping: u64,
    pub send_channel: mpsc::UnboundedSender<Arc<RwLock<ClientState>>>,
}
type SyncConnections = HashMap<Id, RwLock<ConnectionData>>;
type Connections = Arc<RwLock<SyncConnections>>;

#[derive(Clone)]
pub struct Engine {
    pub remote: Remote,
    pub connections: Connections,
}

#[derive(Serialize, Debug)]
pub struct Msg {
    pub id: Id,
    pub content: String,
}

pub trait EventHandler {
    fn new(engine: Engine) -> Self;
    fn main_loop(&self);
    fn message(&self, msg: &Msg);
    fn connect(&self, id: Id) -> bool;
    fn disconnect(&self, id: Id);
}

pub fn execute<T>()
where
    T: EventHandler + Send + Sync + 'static,
{
    dotenv().ok();

    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();

    let server = build_server(&handle);
    let pool = CpuPool::new(3);
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();
    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    let engine = Engine {
        connections: connections.clone(),
        remote: remote.clone(),
    };
    let event_handler = T::new(engine);
    let event_handler = Arc::new(event_handler);

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    let event_handler_inner = event_handler.clone();
    // Handle new connection
    let connection_handler = server
        .incoming()
        .map(|(upgrade, addr)| Some((upgrade, addr)))
        .or_else(|InvalidConnection { error, .. }| {
            println!("Connection dropped: {}", error);
            Ok(None)
        })
        .for_each(move |conn| {
            if conn.is_none() {
                return Ok(());
            }
            let (upgrade, addr) = conn.unwrap();
            let event_handler = event_handler_inner.clone();
            let connections_inner = connections_inner.clone();
            let receive_channel = receive_channel_out.clone();
            let send_channel = send_channel_out.clone();
            let conn_id = conn_id.clone();
            let f = upgrade.accept().and_then(move |(framed, _)| {
                let id = conn_id.borrow_mut().next().expect(
                    "maximum amount of ids reached",
                );
                println!("Got a connection from: {}, assigned id {}", addr, id);
                if !event_handler.connect(id) {
                    return Ok(());
                }
                let (sink, stream) = framed.split();
                let (conn_out, conn_in) = mpsc::unbounded();
                send_channel.send((id, conn_in, sink)).wait().unwrap();
                receive_channel.send((id, stream)).wait().unwrap();
                let data = ConnectionData {
                    ping: 0,
                    send_channel: conn_out,
                };
                connections_inner.write().unwrap().insert(id, RwLock::new(data));
                Ok(())
            });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|e: ()| e);

    // Handle receiving messages from a client
    let connections_inner = connections.clone();
    let event_handler_inner = event_handler.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let connections = connections_inner.clone();
            let event_handler = event_handler_inner.clone();
            remote_inner.spawn(move |_| {
            stream
                .for_each(move |msg| {
                    process_message(id, &msg, &*event_handler, connections.clone());
                    Ok(())
                })
                .map_err(|e| println!("Error while receiving messages: {}", e))
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while receiving messages: {:?}", e));

    // Handle sending messages to a client
    let event_handler_inner = event_handler.clone();
    let send_handler = pool.spawn_fn(move || {
        let remote = remote.clone();
        let connections = connections.clone();
        let event_handler = event_handler_inner.clone();
        send_channel_in.for_each(move |(id, conn_in, sink): (Id, mpsc::UnboundedReceiver<Arc<RwLock<ClientState>>>, SplitSink)| {
            let sink = Arc::new(RwLock::new(sink));
            let connections = connections.clone();
            let event_handler = event_handler.clone();
            remote.spawn(move |_| {
                conn_in.for_each(move |state: Arc<RwLock<ClientState>>| {
                    let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                    // println!("Sending message: {}", msg);
                    let mut sink = sink.write().unwrap();
                    let ok_send = sink.start_send(OwnedMessage::Text(msg)).is_ok();
                    let ok_poll = sink.poll_complete().is_ok();
                    if !ok_send || !ok_poll {
                        println!("Failed to send, kicking client {}", id);
                        kick(&connections, id, &*event_handler);
                    }
                    Ok(())
                })
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while sending messages: {:?}", e));

    // Run maIn loop
    let main_fn = pool.spawn_fn(move || {
        event_handler.main_loop();
        Ok::<(), ()>(())
    }).map_err(|e| println!("Error in main callback function: {:?}", e));
    let handlers = main_fn.select2(connection_handler.select2(
        receive_handler.select(send_handler),
    ));
    core.run(handlers)
        .map_err(|_| println!("Unspecified error while running core loop"))
        .unwrap();
}

pub fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
where
    F: Future<Item = I, Error = E> + 'static,
    E: Debug,
{
    handle.spawn(
        f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
            .map(move |_| ()),
    );
}

fn build_server(handle: &Handle) -> WsServer<NoTlsAcceptor, TcpListener> {
    let address = format!("localhost:{}", read_env_var("CORE_PORT"));
    Server::bind(address, handle).expect("Failed to create server")
}

fn process_message<T>(
    id: Id,
    msg: &OwnedMessage,
    event_handler: &T,
    connections: Connections,
) where
    T: EventHandler,
{
    match *msg {
        OwnedMessage::Pong(_) => {

        }
        OwnedMessage::Text(ref content) => {
            let msg = Msg {
                id,
                content: content.clone(),
            };
            println!("Received message: {}", msg.content);
            event_handler.message(&msg);
        }
        OwnedMessage::Close(_) => {
            kick(&connections, id, event_handler);
        }
        _ => {}
    };
}

fn kick<T>(connections: &Connections, id: Id, event_handler: &T)
where
    T: EventHandler,
{
    connections
        .write()
        .unwrap()
        .remove(&id)
        .and_then(|_| Some(println!("Client with id {} disconnected", id)))
        .expect("Tried to remove id that was not in list");
    event_handler.disconnect(id);
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}
<commit_msg>Core: Rename Counter to IdGen and write test<commit_after>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
extern crate dotenv;

use self::dotenv::dotenv;

use self::websocket::message::OwnedMessage;
use self::websocket::server::{WsServer, InvalidConnection};
use self::websocket::async::{Server, MessageCodec};
use self::websocket::client::async::Framed;
use self::websocket::server::NoTlsAcceptor;

use self::tokio_core::reactor::{Handle, Remote, Core};
use self::tokio_core::net::{TcpStream, TcpListener};

use self::futures::{Future, Sink, Stream};
use self::futures::sync::mpsc;
use self::futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::rc::Rc;
use std::fmt::Debug;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

use model::client::ClientState;
use util::read_env_var;

pub type Id = u32;

type SinkContent = Framed<TcpStream, MessageCodec<OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;

#[derive(Clone)]
pub struct ConnectionData {
    pub ping: u64,
    pub send_channel: mpsc::UnboundedSender<Arc<RwLock<ClientState>>>,
}
type SyncConnections = HashMap<Id, RwLock<ConnectionData>>;
type Connections = Arc<RwLock<SyncConnections>>;

#[derive(Clone)]
pub struct Engine {
    pub remote: Remote,
    pub connections: Connections,
}

#[derive(Serialize, Debug)]
pub struct Msg {
    pub id: Id,
    pub content: String,
}

pub trait EventHandler {
    fn new(engine: Engine) -> Self;
    fn main_loop(&self);
    fn message(&self, msg: &Msg);
    fn connect(&self, id: Id) -> bool;
    fn disconnect(&self, id: Id);
}

pub fn execute<T>()
where
    T: EventHandler + Send + Sync + 'static,
{
    dotenv().ok();

    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();

    let server = build_server(&handle);
    let pool = CpuPool::new(3);
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();
    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    let engine = Engine {
        connections: connections.clone(),
        remote: remote.clone(),
    };
    let event_handler = T::new(engine);
    let event_handler = Arc::new(event_handler);

    let conn_id = Rc::new(RefCell::new(IdGen::new()));
    let connections_inner = connections.clone();
    let event_handler_inner = event_handler.clone();
    // Handle new connection
    let connection_handler = server
        .incoming()
        .map(|(upgrade, addr)| Some((upgrade, addr)))
        .or_else(|InvalidConnection { error, .. }| {
            println!("Connection dropped: {}", error);
            Ok(None)
        })
        .for_each(move |conn| {
            if conn.is_none() {
                return Ok(());
            }
            let (upgrade, addr) = conn.unwrap();
            let event_handler = event_handler_inner.clone();
            let connections_inner = connections_inner.clone();
            let receive_channel = receive_channel_out.clone();
            let send_channel = send_channel_out.clone();
            let conn_id = conn_id.clone();
            let f = upgrade.accept().and_then(move |(framed, _)| {
                let id = conn_id.borrow_mut().next().expect(
                    "maximum amount of ids reached",
                );
                println!("Got a connection from: {}, assigned id {}", addr, id);
                if !event_handler.connect(id) {
                    return Ok(());
                }
                let (sink, stream) = framed.split();
                let (conn_out, conn_in) = mpsc::unbounded();
                send_channel.send((id, conn_in, sink)).wait().unwrap();
                receive_channel.send((id, stream)).wait().unwrap();
                let data = ConnectionData {
                    ping: 0,
                    send_channel: conn_out,
                };
                connections_inner.write().unwrap().insert(id, RwLock::new(data));
                Ok(())
            });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|e: ()| e);

    // Handle receiving messages from a client
    let connections_inner = connections.clone();
    let event_handler_inner = event_handler.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let connections = connections_inner.clone();
            let event_handler = event_handler_inner.clone();
            remote_inner.spawn(move |_| {
            stream
                .for_each(move |msg| {
                    process_message(id, &msg, &*event_handler, connections.clone());
                    Ok(())
                })
                .map_err(|e| println!("Error while receiving messages: {}", e))
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while receiving messages: {:?}", e));

    // Handle sending messages to a client
    let event_handler_inner = event_handler.clone();
    let send_handler = pool.spawn_fn(move || {
        let remote = remote.clone();
        let connections = connections.clone();
        let event_handler = event_handler_inner.clone();
        send_channel_in.for_each(move |(id, conn_in, sink): (Id, mpsc::UnboundedReceiver<Arc<RwLock<ClientState>>>, SplitSink)| {
            let sink = Arc::new(RwLock::new(sink));
            let connections = connections.clone();
            let event_handler = event_handler.clone();
            remote.spawn(move |_| {
                conn_in.for_each(move |state: Arc<RwLock<ClientState>>| {
                    let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                    // println!("Sending message: {}", msg);
                    let mut sink = sink.write().unwrap();
                    let ok_send = sink.start_send(OwnedMessage::Text(msg)).is_ok();
                    let ok_poll = sink.poll_complete().is_ok();
                    if !ok_send || !ok_poll {
                        println!("Failed to send, kicking client {}", id);
                        kick(&connections, id, &*event_handler);
                    }
                    Ok(())
                })
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while sending messages: {:?}", e));

    // Run maIn loop
    let main_fn = pool.spawn_fn(move || {
        event_handler.main_loop();
        Ok::<(), ()>(())
    }).map_err(|e| println!("Error in main callback function: {:?}", e));
    let handlers = main_fn.select2(connection_handler.select2(
        receive_handler.select(send_handler),
    ));
    core.run(handlers)
        .map_err(|_| println!("Unspecified error while running core loop"))
        .unwrap();
}

pub fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
where
    F: Future<Item = I, Error = E> + 'static,
    E: Debug,
{
    handle.spawn(
        f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
            .map(move |_| ()),
    );
}

fn build_server(handle: &Handle) -> WsServer<NoTlsAcceptor, TcpListener> {
    let address = format!("localhost:{}", read_env_var("CORE_PORT"));
    Server::bind(address, handle).expect("Failed to create server")
}

fn process_message<T>(
    id: Id,
    msg: &OwnedMessage,
    event_handler: &T,
    connections: Connections,
) where
    T: EventHandler,
{
    match *msg {
        OwnedMessage::Pong(_) => {

        }
        OwnedMessage::Text(ref content) => {
            let msg = Msg {
                id,
                content: content.clone(),
            };
            println!("Received message: {}", msg.content);
            event_handler.message(&msg);
        }
        OwnedMessage::Close(_) => {
            kick(&connections, id, event_handler);
        }
        _ => {}
    };
}

fn kick<T>(connections: &Connections, id: Id, event_handler: &T)
where
    T: EventHandler,
{
    connections
        .write()
        .unwrap()
        .remove(&id)
        .and_then(|_| Some(println!("Client with id {} disconnected", id)))
        .expect("Tried to remove id that was not in list");
    event_handler.disconnect(id);
}

struct IdGen {
    count: Id,
}
impl IdGen {
    fn new() -> Self {
        IdGen { count: 0 }
    }
}

impl Iterator for IdGen {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[test]
fn id_gen_unique() {
    let mut id_gen = IdGen::new();
    let mut ids = Vec::new();
    let ids_count = 1000;
    for _ in 0..ids_count {
        ids.push(id_gen.next());
    }
    ids.sort();
    ids.dedup_by_key(|id| *id);
    assert_eq!(ids_count, ids.len());
}
<|endoftext|>