<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/. */

use dom::bindings::codegen::BindingDeclarations::HTMLTableRowElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableRowElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableRowElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableRowElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableRowElementDerived for EventTarget {
    fn is_htmltablerowelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableRowElementTypeId))
    }
}

impl HTMLTableRowElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableRowElement {
        HTMLTableRowElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableRowElement> {
        let element = HTMLTableRowElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableRowElementBinding::Wrap)
    }
}

pub trait HTMLTableRowElementMethods {
    fn RowIndex(&self) -> i32;
    fn GetRowIndex(&self) -> i32;
    fn SectionRowIndex(&self) -> i32;
    fn GetSectionRowIndex(&self) -> i32;
    fn DeleteCell(&mut self, _index: i32) -> ErrorResult;
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Ch(&self) -> DOMString;
    fn SetCh(&self, _ch: DOMString) -> ErrorResult;
    fn ChOff(&self) -> DOMString;
    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult;
    fn VAlign(&self) -> DOMString;
    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult;
    fn BgColor(&self) -> DOMString;
    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableRowElementMethods for JSRef<'a, HTMLTableRowElement> {
    fn RowIndex(&self) -> i32 {
        0
    }

    fn GetRowIndex(&self) -> i32 {
        0
    }

    fn SectionRowIndex(&self) -> i32 {
        0
    }

    fn GetSectionRowIndex(&self) -> i32 {
        0
    }

    fn DeleteCell(&mut self, _index: i32) -> ErrorResult {
        Ok(())
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Ch(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCh(&self, _ch: DOMString) -> ErrorResult {
        Ok(())
    }

    fn ChOff(&self) -> DOMString {
        "".to_owned()
    }

    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult {
        Ok(())
    }

    fn VAlign(&self) -> DOMString {
        "".to_owned()
    }

    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn BgColor(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLTableRawElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLTableRowElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableRowElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableRowElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableRowElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableRowElementDerived for EventTarget {
    fn is_htmltablerowelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableRowElementTypeId))
    }
}

impl HTMLTableRowElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableRowElement {
        HTMLTableRowElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableRowElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableRowElement> {
        let element = HTMLTableRowElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableRowElementBinding::Wrap)
    }
}

pub trait HTMLTableRowElementMethods {
    fn RowIndex(&self) -> i32;
    fn GetRowIndex(&self) -> i32;
    fn SectionRowIndex(&self) -> i32;
    fn GetSectionRowIndex(&self) -> i32;
    fn DeleteCell(&self, _index: i32) -> ErrorResult;
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Ch(&self) -> DOMString;
    fn SetCh(&self, _ch: DOMString) -> ErrorResult;
    fn ChOff(&self) -> DOMString;
    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult;
    fn VAlign(&self) -> DOMString;
    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult;
    fn BgColor(&self) -> DOMString;
    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableRowElementMethods for JSRef<'a, HTMLTableRowElement> {
    fn RowIndex(&self) -> i32 {
        0
    }

    fn GetRowIndex(&self) -> i32 {
        0
    }

    fn SectionRowIndex(&self) -> i32 {
        0
    }

    fn GetSectionRowIndex(&self) -> i32 {
        0
    }

    fn DeleteCell(&self, _index: i32) -> ErrorResult {
        Ok(())
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Ch(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCh(&self, _ch: DOMString) -> ErrorResult {
        Ok(())
    }

    fn ChOff(&self) -> DOMString {
        "".to_owned()
    }

    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult {
        Ok(())
    }

    fn VAlign(&self) -> DOMString {
        "".to_owned()
    }

    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn BgColor(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use lsp_types::{Position, Range};
use serde::{Deserialize, Serialize};

/// Represents GraphQL text extracted from a JS-like source
/// file. Stores the text and some location information for
/// error reporting.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct GraphQLSource {
    pub text: String,
    pub line_index: usize,
    pub column_index: usize,
}

impl GraphQLSource {
    pub fn new(text: impl Into<String>, line_index: usize, column_index: usize) -> Self {
        GraphQLSource {
            text: text.into(),
            line_index,
            column_index,
        }
    }

    // Generate an LSP Range for this GraphQL source string. This provides the absolute
    // range of the entire GraphQL string within the source file.
    pub fn to_range(&self) -> Range {
        // Zero-indexed line offset in the document
        let mut line = self.line_index;
        // Zero-indexed character offset on the line
        let mut character = self.column_index;
        let mut chars = self.text.chars().peekable();
        let start_position = Position::new(line as u32, character as u32);
        while let Some(chr) = chars.next() {
            let is_newline = match chr {
                // Line terminators: https://www.ecma-international.org/ecma-262/#sec-line-terminators
                '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' => {
                    !matches!((chr, chars.peek()), ('\u{000D}', Some('\u{000D}')))
                }
                _ => false,
            };

            if is_newline {
                // New line, increment the line offset and reset the
                // character offset.
                line += 1;
                character = 0;
            }
            // Make sure to only increment the character offset if this
            // isn't a newline.
            if !is_newline {
                character += 1;
            }
        }
        let end_position = Position::new(line as u32, character as u32);
        Range::new(start_position, end_position)
    }
}
<commit_msg>Add changed documents to LSP state<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use lsp_types::{Position, Range};
use serde::{Deserialize, Serialize};

/// Represents GraphQL text extracted from a source file
/// The GraphQL text is potentially in some subrange of
/// the file, like a JS file.
/// Stores the text and some location information for
/// error reporting.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct GraphQLSource {
    pub text: String,
    pub line_index: usize,
    pub column_index: usize,
}

impl GraphQLSource {
    pub fn new(text: impl Into<String>, line_index: usize, column_index: usize) -> Self {
        GraphQLSource {
            text: text.into(),
            line_index,
            column_index,
        }
    }

    pub fn from_whole_document(text: impl Into<String>) -> Self {
        GraphQLSource::new(text, 0, 0)
    }

    // Generate an LSP Range for this GraphQL source string. This provides the absolute
    // range of the entire GraphQL string within the source file.
    pub fn to_range(&self) -> Range {
        // Zero-indexed line offset in the document
        let mut line = self.line_index;
        // Zero-indexed character offset on the line
        let mut character = self.column_index;
        let mut chars = self.text.chars().peekable();
        let start_position = Position::new(line as u32, character as u32);
        while let Some(chr) = chars.next() {
            let is_newline = match chr {
                // Line terminators: https://www.ecma-international.org/ecma-262/#sec-line-terminators
                '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' => {
                    !matches!((chr, chars.peek()), ('\u{000D}', Some('\u{000D}')))
                }
                _ => false,
            };

            if is_newline {
                // New line, increment the line offset and reset the
                // character offset.
                line += 1;
                character = 0;
            }
            // Make sure to only increment the character offset if this
            // isn't a newline.
            if !is_newline {
                character += 1;
            }
        }
        let end_position = Position::new(line as u32, character as u32);
        Range::new(start_position, end_position)
    }
}
<|endoftext|>


<commit_before>extern crate regex;
use self::regex::Regex;

pub struct LsbRelease {
    pub distro: Option<String>,
    pub version: Option<String>
}

pub fn parse(file: String) -> LsbRelease {
    let distrib_regex = Regex::new(r"DISTRIB_ID=(\w+)").unwrap();
    let distrib_release_regex = Regex::new(r"DISTRIB_RELEASE=([\w\.]+)").unwrap();

    let distro = match distrib_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(distro) => {
                    println!("Match {}", distro);
                    Some(distro.to_string())
                },
                None => None
            }
        },
        None => None
    };

    let version = match distrib_release_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(version) => Some(version.to_string()),
                None => None
            }
        },
        None => None
    };

    LsbRelease {
        distro: distro,
        version: version
    }
}
<commit_msg>remove debug output<commit_after>extern crate regex;
use self::regex::Regex;

pub struct LsbRelease {
    pub distro: Option<String>,
    pub version: Option<String>
}

pub fn parse(file: String) -> LsbRelease {
    let distrib_regex = Regex::new(r"DISTRIB_ID=(\w+)").unwrap();
    let distrib_release_regex = Regex::new(r"DISTRIB_RELEASE=([\w\.]+)").unwrap();

    let distro = match distrib_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(distro) => {
                    Some(distro.to_string())
                },
                None => None
            }
        },
        None => None
    };

    let version = match distrib_release_regex.captures_iter(&file).next() {
        Some(m) => {
            match m.at(1) {
                Some(version) => Some(version.to_string()),
                None => None
            }
        },
        None => None
    };

    LsbRelease {
        distro: distro,
        version: version
    }
}
<|endoftext|>


<commit_before>use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, Utc, DateTime};

use apple_music;
use youtube;
use youtube::HasThumbnail;
use soundcloud;
use spotify;
use error::Error;
use super::{conn, Model};
use model::provider::Provider;
use model::state::State;
use model::enclosure::Enclosure;
use model::track::Track;

static PROPS: [&'static str; 14]  = ["id",
                                     "provider",
                                     "identifier",
                                     "owner_id",
                                     "owner_name",
                                     "url",
                                     "title",
                                     "description",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Playlist {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub owner_id:      Option<String>,
    pub owner_name:    Option<String>,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
    pub tracks:        Vec<Track>,
}

impl PartialEq for Playlist {
    fn eq(&self, p: &Playlist) -> bool {
        return self.identifier == p.identifier && self.provider == p.provider
    }
}

impl fmt::Display for Playlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl<'a> Model<'a> for Playlist {
    fn table_name() -> String { "playlists".to_string() }
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn row_to_item(row: postgres::rows::Row) -> Playlist {
        Playlist {
            id:            row.get(0),
            provider:      Provider::new(row.get(1)),
            identifier:    row.get(2),
            owner_id:      row.get(3),
            owner_name:    row.get(4),
            url:           row.get(5),
            title:         row.get(6),
            description:   row.get(7),
            thumbnail_url: row.get(8),
            artwork_url:   row.get(9),
            published_at:  row.get(10),
            created_at:    row.get(11),
            updated_at:    row.get(12),
            state:         State::new(row.get(13)),
            tracks:        vec![], // TODO
        }
    }
    fn create(&self) -> Result<Playlist, Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlists (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id")?;
        let rows = stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title])?;
        let mut playlist = self.clone();
        for row in rows.iter() {
            playlist.id = row.get(0);
        }
        Ok(playlist)
    }

    fn save(&mut self) -> Result<(), Error> {
        self.updated_at = Utc::now().naive_utc();
        let conn = conn()?;
        let stmt = conn.prepare("UPDATE playlists SET
                                      provider      = $2,
                                      identifier    = $3,
                                      owner_id      = $4,
                                      owner_name    = $5,
                                      url           = $6,
                                      title         = $7,
                                      description   = $8,
                                      thumbnail_url = $9,
                                      artwork_url   = $10,
                                      published_at  = $11,
                                      created_at    = $12,
                                      updated_at    = $13,
                                      state         = $14
                                      WHERE id = $1")?;
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.owner_id,
                                  &self.owner_name,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected),
        }
    }
}

impl<'a> Enclosure<'a> for Playlist {
    fn new(provider: Provider, identifier: String) -> Playlist {
        Playlist {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            owner_id:      None,
            owner_name:    None,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            thumbnail_url: None,
            artwork_url:   None,
            published_at:  Utc::now().naive_utc(),
            created_at:    Utc::now().naive_utc(),
            updated_at:    Utc::now().naive_utc(),
            state:         State::Alive,
            tracks:        vec![],
        }
    }
    fn set_url(&mut self, url: String) -> &mut Playlist {
        self.url = url;
        self
    }
    fn set_owner_id(&mut self, owner_id: Option<String>) -> &mut Playlist {
        self.owner_id = owner_id;
        self
    }
    fn fetch_props(&mut self) -> Result<(), Error> {
        match self.provider {
            Provider::YouTube => {
                let items = youtube::fetch_playlist_items(&self.identifier)
                    .map(|res| res.items)
                    .unwrap_or(vec![]);
                if let Ok(res) = youtube::fetch_playlist(&self.identifier) {
                    if let Some(playlist) = res.items.iter().nth(0) {
                        self.update_with_yt_playlist(&playlist, &items);
                    }
                }
                self.disable();
            },
            Provider::SoundCloud => {
                match soundcloud::fetch_playlist(&self.identifier) {
                    Ok(playlist) => self.update_with_sc_playlist(&playlist),
                    Err(_)       => self.disable()
                };
            },
            Provider::AppleMusic => {
                let country = apple_music::country(&self.url);
                match apple_music::fetch_playlist(&self.identifier, &country) {
                    Ok(playlist) => self.update_with_am_playlist(&playlist),
                    Err(_)       => self.disable(),
                };
            },
            Provider::Spotify => {
                if let Some(owner_id) = self.clone().owner_id {
                    match spotify::fetch_playlist(&owner_id, &self.identifier) {
                        Ok(playlist) => {
                            self.update_with_sp_playlist(&playlist);
                        },
                        Err(_)       => {
                            self.disable();
                        },
                    }
                }
            },
            _ => (),
        };
        match self.state {
            State::Alive => Ok(()),
            State::Dead  => Err(Error::NotFound),
        }
    }
    fn find_by_entry_id(entry_id: Uuid) -> Vec<Playlist> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists p LEFT JOIN playlist_entries pe
                        ON p.id = pe.playlist_id
                        WHERE pe.entry_id = $1
                        ORDER BY p.published_at DESC",
                     Playlist::props_str("p."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Playlist::rows_to_items(rows)
    }
}

impl Playlist {
    pub fn add_track(&mut self, track: &Track) -> Result<(), Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlist_tracks (track_id, playlist_id)
                                      VALUES ($1, $2)")?;
        stmt.query(&[&track.id, &self.id])?;
        Ok(())
    }

    pub fn from_yt_playlist(playlist: &youtube::Playlist, items: &Vec<youtube::PlaylistItem>) -> Playlist {
        Playlist::find_or_create(Provider::YouTube, (*playlist).id.to_string())
            .unwrap()
            .update_with_yt_playlist(playlist, items)
            .clone()
    }

    pub fn from_sp_playlist(playlist: &spotify::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::Spotify, (*playlist).id.to_string())
            .unwrap()
            .update_with_sp_playlist(playlist)
            .clone()
    }

    pub fn from_sc_playlist(playlist: &soundcloud::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::SoundCloud, (*playlist).id.to_string())
            .unwrap()
            .update_with_sc_playlist(playlist)
            .clone()
    }

    pub fn from_am_playlist(playlist: &apple_music::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::AppleMusic, (*playlist).id.to_string())
            .unwrap()
            .update_with_am_playlist(playlist)
            .clone()
    }

    fn add_tracks(&mut self, tracks: Vec<Track>) {
        self.tracks = tracks.iter().map(|t| {
            let mut t = t.clone();
            if let Ok(new_track) = Track::find_or_create(t.provider,
                                                         t.identifier.to_string()) {
                t.id      = new_track.id;
                let _     = t.save();
                let _     = self.add_track(&t);
            };
            t
        }).collect::<Vec<_>>();
    }

    pub fn update_with_yt_playlist(&mut self, playlist: &youtube::Playlist, items: &Vec<youtube::PlaylistItem>) -> &mut Playlist {
        self.provider      = Provider::YouTube;
        self.identifier    = playlist.id.to_string();
        self.owner_id      = Some(playlist.snippet.channelId.to_string());
        self.owner_name    = Some(playlist.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/playlist?list={}", playlist.id);
        self.title         = playlist.snippet.title.to_string();
        self.description   = Some(playlist.snippet.description.to_string());
        self.thumbnail_url = playlist.snippet.get_thumbnail_url();
        self.artwork_url   = playlist.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&playlist.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        let tracks = items.iter()
            .map(|ref i| Track::from_yt_playlist_item(i))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_sp_playlist(&mut self, playlist: &spotify::Playlist) -> &mut Playlist {
        self.provider       = Provider::Spotify;
        self.identifier     = playlist.id.to_string();
        self.owner_id       = Some(playlist.owner.id.to_string());
        self.owner_name     = playlist.owner.display_name.clone();
        self.url            = playlist.uri.clone();
        self.title          = playlist.name.clone();
        self.description    = playlist.description.clone();
        self.state          = State::Alive;
        self.published_at   = Utc::now().naive_utc();
        if playlist.images.len() > 0 {
            self.artwork_url   = Some(playlist.images[0].url.clone());
            self.thumbnail_url = Some(playlist.images[0].url.clone());
        }
        if playlist.images.len() > 1 {
            self.thumbnail_url = Some(playlist.images[1].url.clone());
        }
        let tracks = playlist.tracks.items.iter()
            .map(|ref i| Track::from_sp_track(&i.track))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_sc_playlist(&mut self, playlist: &soundcloud::Playlist) -> &mut Playlist {
        self.provider      = Provider::SoundCloud;
        self.identifier    = playlist.id.to_string();
        self.owner_id      = Some(playlist.user.id.to_string());
        self.owner_name    = Some(playlist.user.username.clone());
        self.url           = playlist.permalink_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = None;
        self.thumbnail_url = playlist.artwork_url.clone();
        self.artwork_url   = playlist.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&playlist.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        };
        let tracks = playlist.tracks.iter()
            .map(|ref t| Track::from_sc_track(t))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_am_playlist(&mut self, playlist: &apple_music::Playlist) -> &mut Playlist {
        let curator = playlist.clone().relationships.map(|r| {
            r.curator.data.clone()
        }).unwrap_or(vec![]);
        self.provider      = Provider::AppleMusic;
        self.identifier    = playlist.id.clone();
        self.owner_id      = curator.first().map(|c| c.id.clone());
        self.owner_name    = playlist.attributes.curator_name.clone();
        self.url           = playlist.attributes.url.clone();
        self.title         = playlist.attributes.name.clone();
        self.description   = playlist.attributes.description.clone().and_then(|d| d.short.clone());
        self.thumbnail_url = playlist.attributes.artwork.clone().map(|a| a.get_thumbnail_url());
        self.artwork_url   = playlist.attributes.artwork.clone().map(|a| a.get_artwork_url());
        self.state         = State::Alive;
        self
    }

    pub fn disable(&mut self) -> &mut Playlist {
        self.state = State::Dead;
        self
    }

    pub fn delete(&self) -> Result<(), Error> {
        let conn = conn()?;
        let stmt = conn.prepare("DELETE FROM playlists WHERE id=$1")?;
        let result = stmt.query(&[&self.id]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

#[cfg(test)]
mod test {
    use model::enclosure::Enclosure;
    use model::Model;
    use super::Playlist;
    use Provider;
    #[test]
    fn test_new() {
        let playlist = Playlist::new(Provider::YouTube,
                                     "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string());
        assert_eq!(playlist.provider, Provider::YouTube);
        assert_eq!(&playlist.identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX")
    }
    #[test]
    fn test_find_of_create() {
        let identifier = "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string();
        let result     = Playlist::find_or_create(Provider::YouTube, identifier);
        assert!(result.is_ok());
    }
    #[test]
    fn test_delete() {
        let identifier = "test_delete".to_string();
        let playlist   = Playlist::find_or_create(Provider::YouTube, identifier).unwrap();
        let result     = playlist.delete();
        assert!(result.is_ok());
    }
    #[test]
    fn test_save() {
        let id = "test_save";
        let mut playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        playlist.title = "title".to_string();
        let result = playlist.save();
        assert!(result.is_ok());
        let playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        assert_eq!(&playlist.title, "title");
    }
}
<commit_msg>Add velocity to Playlist struct<commit_after>use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, Utc, DateTime};

use apple_music;
use youtube;
use youtube::HasThumbnail;
use soundcloud;
use spotify;
use error::Error;
use super::{conn, Model};
use model::provider::Provider;
use model::state::State;
use model::enclosure::Enclosure;
use model::track::Track;

static PROPS: [&'static str; 15]  = ["id",
                                     "provider",
                                     "identifier",
                                     "owner_id",
                                     "owner_name",
                                     "url",
                                     "title",
                                     "description",
                                     "velocity",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Playlist {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub owner_id:      Option<String>,
    pub owner_name:    Option<String>,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub velocity:      f64,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
    pub tracks:        Vec<Track>,
}

impl PartialEq for Playlist {
    fn eq(&self, p: &Playlist) -> bool {
        return self.identifier == p.identifier && self.provider == p.provider
    }
}

impl fmt::Display for Playlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl<'a> Model<'a> for Playlist {
    fn table_name() -> String { "playlists".to_string() }
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn row_to_item(row: postgres::rows::Row) -> Playlist {
        Playlist {
            id:            row.get(0),
            provider:      Provider::new(row.get(1)),
            identifier:    row.get(2),
            owner_id:      row.get(3),
            owner_name:    row.get(4),
            url:           row.get(5),
            title:         row.get(6),
            description:   row.get(7),
            velocity:      row.get(8),
            thumbnail_url: row.get(9),
            artwork_url:   row.get(10),
            published_at:  row.get(11),
            created_at:    row.get(12),
            updated_at:    row.get(13),
            state:         State::new(row.get(14)),
            tracks:        vec![], // TODO
        }
    }
    fn create(&self) -> Result<Playlist, Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlists (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id")?;
        let rows = stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title])?;
        let mut playlist = self.clone();
        for row in rows.iter() {
            playlist.id = row.get(0);
        }
        Ok(playlist)
    }

    fn save(&mut self) -> Result<(), Error> {
        self.updated_at = Utc::now().naive_utc();
        let conn = conn()?;
        let stmt = conn.prepare("UPDATE playlists SET
                                      provider      = $2,
                                      identifier    = $3,
                                      owner_id      = $4,
                                      owner_name    = $5,
                                      url           = $6,
                                      title         = $7,
                                      description   = $8,
                                      velocity      = $9,
                                      thumbnail_url = $10,
                                      artwork_url   = $11,
                                      published_at  = $12,
                                      created_at    = $13,
                                      updated_at    = $14,
                                      state         = $15
                                      WHERE id = $1")?;
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.owner_id,
                                  &self.owner_name,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.velocity,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected),
        }
    }
}

impl<'a> Enclosure<'a> for Playlist {
    fn new(provider: Provider, identifier: String) -> Playlist {
        Playlist {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            owner_id:      None,
            owner_name:    None,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            velocity:      0.0,
            thumbnail_url: None,
            artwork_url:   None,
            published_at:  Utc::now().naive_utc(),
            created_at:    Utc::now().naive_utc(),
            updated_at:    Utc::now().naive_utc(),
            state:         State::Alive,
            tracks:        vec![],
        }
    }
    fn set_url(&mut self, url: String) -> &mut Playlist {
        self.url = url;
        self
    }
    fn set_owner_id(&mut self, owner_id: Option<String>) -> &mut Playlist {
        self.owner_id = owner_id;
        self
    }
    fn fetch_props(&mut self) -> Result<(), Error> {
        match self.provider {
            Provider::YouTube => {
                let items = youtube::fetch_playlist_items(&self.identifier)
                    .map(|res| res.items)
                    .unwrap_or(vec![]);
                if let Ok(res) = youtube::fetch_playlist(&self.identifier) {
                    if let Some(playlist) = res.items.iter().nth(0) {
                        self.update_with_yt_playlist(&playlist, &items);
                    }
                }
                self.disable();
            },
            Provider::SoundCloud => {
                match soundcloud::fetch_playlist(&self.identifier) {
                    Ok(playlist) => self.update_with_sc_playlist(&playlist),
                    Err(_)       => self.disable()
                };
            },
            Provider::AppleMusic => {
                let country = apple_music::country(&self.url);
                match apple_music::fetch_playlist(&self.identifier, &country) {
                    Ok(playlist) => self.update_with_am_playlist(&playlist),
                    Err(_)       => self.disable(),
                };
            },
            Provider::Spotify => {
                if let Some(owner_id) = self.clone().owner_id {
                    match spotify::fetch_playlist(&owner_id, &self.identifier) {
                        Ok(playlist) => {
                            self.update_with_sp_playlist(&playlist);
                        },
                        Err(_)       => {
                            self.disable();
                        },
                    }
                }
            },
            _ => (),
        };
        match self.state {
            State::Alive => Ok(()),
            State::Dead  => Err(Error::NotFound),
        }
    }
    fn find_by_entry_id(entry_id: Uuid) -> Vec<Playlist> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists p LEFT JOIN playlist_entries pe
                        ON p.id = pe.playlist_id
                        WHERE pe.entry_id = $1
                        ORDER BY p.published_at DESC",
                     Playlist::props_str("p."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Playlist::rows_to_items(rows)
    }
}

impl Playlist {
    pub fn add_track(&mut self, track: &Track) -> Result<(), Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlist_tracks (track_id, playlist_id)
                                      VALUES ($1, $2)")?;
        stmt.query(&[&track.id, &self.id])?;
        Ok(())
    }

    pub fn from_yt_playlist(playlist: &youtube::Playlist, items: &Vec<youtube::PlaylistItem>) -> Playlist {
        Playlist::find_or_create(Provider::YouTube, (*playlist).id.to_string())
            .unwrap()
            .update_with_yt_playlist(playlist, items)
            .clone()
    }

    pub fn from_sp_playlist(playlist: &spotify::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::Spotify, (*playlist).id.to_string())
            .unwrap()
            .update_with_sp_playlist(playlist)
            .clone()
    }

    pub fn from_sc_playlist(playlist: &soundcloud::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::SoundCloud, (*playlist).id.to_string())
            .unwrap()
            .update_with_sc_playlist(playlist)
            .clone()
    }

    pub fn from_am_playlist(playlist: &apple_music::Playlist) -> Playlist {
        Playlist::find_or_create(Provider::AppleMusic, (*playlist).id.to_string())
            .unwrap()
            .update_with_am_playlist(playlist)
            .clone()
    }

    fn add_tracks(&mut self, tracks: Vec<Track>) {
        self.tracks = tracks.iter().map(|t| {
            let mut t = t.clone();
            if let Ok(new_track) = Track::find_or_create(t.provider,
                                                         t.identifier.to_string()) {
                t.id      = new_track.id;
                let _     = t.save();
                let _     = self.add_track(&t);
            };
            t
        }).collect::<Vec<_>>();
    }

    pub fn update_with_yt_playlist(&mut self, playlist: &youtube::Playlist, items: &Vec<youtube::PlaylistItem>) -> &mut Playlist {
        self.provider      = Provider::YouTube;
        self.identifier    = playlist.id.to_string();
        self.owner_id      = Some(playlist.snippet.channelId.to_string());
        self.owner_name    = Some(playlist.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/playlist?list={}", playlist.id);
        self.title         = playlist.snippet.title.to_string();
        self.description   = Some(playlist.snippet.description.to_string());
        self.thumbnail_url = playlist.snippet.get_thumbnail_url();
        self.artwork_url   = playlist.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&playlist.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        let tracks = items.iter()
            .map(|ref i| Track::from_yt_playlist_item(i))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_sp_playlist(&mut self, playlist: &spotify::Playlist) -> &mut Playlist {
        self.provider       = Provider::Spotify;
        self.identifier     = playlist.id.to_string();
        self.owner_id       = Some(playlist.owner.id.to_string());
        self.owner_name     = playlist.owner.display_name.clone();
        self.url            = playlist.uri.clone();
        self.title          = playlist.name.clone();
        self.description    = playlist.description.clone();
        self.state          = State::Alive;
        self.published_at   = Utc::now().naive_utc();
        if playlist.images.len() > 0 {
            self.artwork_url   = Some(playlist.images[0].url.clone());
            self.thumbnail_url = Some(playlist.images[0].url.clone());
        }
        if playlist.images.len() > 1 {
            self.thumbnail_url = Some(playlist.images[1].url.clone());
        }
        let tracks = playlist.tracks.items.iter()
            .map(|ref i| Track::from_sp_track(&i.track))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_sc_playlist(&mut self, playlist: &soundcloud::Playlist) -> &mut Playlist {
        self.provider      = Provider::SoundCloud;
        self.identifier    = playlist.id.to_string();
        self.owner_id      = Some(playlist.user.id.to_string());
        self.owner_name    = Some(playlist.user.username.clone());
        self.url           = playlist.permalink_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = None;
        self.thumbnail_url = playlist.artwork_url.clone();
        self.artwork_url   = playlist.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&playlist.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        };
        let tracks = playlist.tracks.iter()
            .map(|ref t| Track::from_sc_track(t))
            .collect::<Vec<_>>();
        self.add_tracks(tracks);
        self
    }

    pub fn update_with_am_playlist(&mut self, playlist: &apple_music::Playlist) -> &mut Playlist {
        let curator = playlist.clone().relationships.map(|r| {
            r.curator.data.clone()
        }).unwrap_or(vec![]);
        self.provider      = Provider::AppleMusic;
        self.identifier    = playlist.id.clone();
        self.owner_id      = curator.first().map(|c| c.id.clone());
        self.owner_name    = playlist.attributes.curator_name.clone();
        self.url           = playlist.attributes.url.clone();
        self.title         = playlist.attributes.name.clone();
        self.description   = playlist.attributes.description.clone().and_then(|d| d.short.clone());
        self.thumbnail_url = playlist.attributes.artwork.clone().map(|a| a.get_thumbnail_url());
        self.artwork_url   = playlist.attributes.artwork.clone().map(|a| a.get_artwork_url());
        self.state         = State::Alive;
        self
    }

    pub fn disable(&mut self) -> &mut Playlist {
        self.state = State::Dead;
        self
    }

    pub fn delete(&self) -> Result<(), Error> {
        let conn = conn()?;
        let stmt = conn.prepare("DELETE FROM playlists WHERE id=$1")?;
        let result = stmt.query(&[&self.id]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

#[cfg(test)]
mod test {
    use model::enclosure::Enclosure;
    use model::Model;
    use super::Playlist;
    use Provider;
    #[test]
    fn test_new() {
        let playlist = Playlist::new(Provider::YouTube,
                                     "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string());
        assert_eq!(playlist.provider, Provider::YouTube);
        assert_eq!(&playlist.identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX")
    }
    #[test]
    fn test_find_of_create() {
        let identifier = "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string();
        let result     = Playlist::find_or_create(Provider::YouTube, identifier);
        assert!(result.is_ok());
    }
    #[test]
    fn test_delete() {
        let identifier = "test_delete".to_string();
        let playlist   = Playlist::find_or_create(Provider::YouTube, identifier).unwrap();
        let result     = playlist.delete();
        assert!(result.is_ok());
    }
    #[test]
    fn test_save() {
        let id = "test_save";
        let mut playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        playlist.title = "title".to_string();
        let result = playlist.save();
        assert!(result.is_ok());
        let playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        assert_eq!(&playlist.title, "title");
    }
}
<|endoftext|>


<commit_before>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: isize,
}

/// `Instruction`s are executed by a `Node`.
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
pub enum Destination {
    /// A register
    Register(Register),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0 }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: isize) -> Node {
        Node { pc: pc, .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: isize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }
}

<commit_msg>Introduce a progam<commit_after>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Result};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: isize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: isize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: isize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }
}

<|endoftext|>


<commit_before>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Result};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: isize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: isize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: isize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }
}

<commit_msg>Use standard Result<commit_after>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: isize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: isize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: isize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::marker::PhantomData;

#[derive(Copy, Clone, Debug, EnumMap, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn discriminants() {
    #[derive(Debug, EnumMap, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example:: A => 3, Example:: B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(EnumMap)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }.into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}
<commit_msg>Add a test for collecting reversed values<commit_after>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::marker::PhantomData;

#[derive(Copy, Clone, Debug, EnumMap, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn discriminants() {
    #[derive(Debug, EnumMap, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example:: A => 3, Example:: B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(EnumMap)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }.into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}
<|endoftext|>