<commit_before>use serde;
use serde_json;
use serde_yaml;
use uuid::Uuid;

use structure::translation::TranslationDocument;
use dsl::command::{GearsDsl, DslTree, DslToken, DslTokens, command_grammar};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Document<T> {
    pub id: Uuid,
    pub name: String,
    pub doctype: String,
    pub doctype_version: i64,
    pub version: i64,
    pub doc: T,
}

pub type DocumentList<T> = Vec<Document<T>>;

impl<T> Document<T>
where
    T: serde::Serialize + serde::de::DeserializeOwned + Eq + Default,
{
    pub fn new_from_header(header: &DocumentHeader) -> Self {
        Self {
            id: header.id.clone(),
            name: header.name.clone(),
            doctype: header.doctype.clone(),
            doctype_version: header.doctype_version.clone(),
            version: header.version.clone(),
            doc: <T>::default(),
        }
    }

    pub fn get_header(&self) -> DocumentHeader {
        DocumentHeader {
            id: self.id.clone(),
            name: self.name.clone(),
            doctype: self.doctype.clone(),
            doctype_version: self.doctype_version.clone(),
            version: self.version.clone(),
        }
    }

    pub fn set_header(&mut self, header: &DocumentHeader) -> () {
        self.id = header.id.clone();
        self.name = header.name.clone();
        self.doctype = header.doctype.clone();
        self.doctype_version = header.doctype_version.clone();
        self.version = header.version.clone();
    }

    /// Return a string representation of the Document
    ///
    pub fn to_string(&self) -> String {
        format!("document {}", self.id)
    }

    /// Return a summary of the Document
    ///
    pub fn summary(&self) -> String {
        format!("Doc {:?} - {:?} - {:?}", self.doctype, self.id, self.name)
    }

    /// Return an indented JSON representation of the Document
    ///
    /// partof: SPC-serialization-json
    pub fn to_json(&self) -> String {
        serde_json::to_string_pretty(&self).unwrap()
    }

    /// Return a compact JSON representation of the Document
    ///
    /// partof: SPC-serialization-json
    pub fn to_json_compact(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }

    /// Initialize a Document from a JSON string
    ///
    /// partof: SPC-serialization-json
    pub fn from_json(s: &str) -> Self {
        serde_json::from_str(s).unwrap()
    }

    /// Return a YAML representation of the Document
    ///
    /// partof: #SPC-serialization-yaml
    pub fn to_yaml(&self) -> String {
        serde_yaml::to_string(&self).unwrap()
    }

    /// Initialize a Document from a JSON string
    ///
    /// partof: SPC-serialization-yaml
    pub fn from_yaml(s: &str) -> Self {
        serde_yaml::from_str(s).unwrap()
    }
}

impl<T> Default for Document<T>
where
    T: Default,
{
    fn default() -> Self {
        Self {
            id: Uuid::new_v4(),
            name: "default".to_owned(),
            doctype: "".to_owned(),
            doctype_version: 1,
            version: 1,
            doc: <T>::default(),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum DocumentListCommand {
    Add(String),
    Remove(String),
    List,
    Show(String),
}

impl DocumentListCommand {
    fn as_dsl_token(&self) -> DslToken {
        let s = match *self {
            DocumentListCommand::Add(ref e) => format!("add {}", e),
            DocumentListCommand::Remove(ref e) => format!("remove {}", e),
            DocumentListCommand::List => format!("list"),
            DocumentListCommand::Show(ref e) => format!("show {}", e),
        };
        DslToken::Command(s)
    }
}

use std::fmt::Debug;

impl<T> GearsDsl for DocumentList<T>
where
    T: Default + Debug,
{
    fn generate_dsl(&self) -> DslTokens {
        let mut res = DslTokens::new();

        for doc in self {
            res.push(DocumentListCommand::Add(doc.name.clone()).as_dsl_token());
        }

        res
    }

    fn consume_command(&mut self, s: &str) -> Result<(), String> {
        debug!("consume_command : received command string '{:?}'", s);
        match command_grammar::document_list_command(&s) {
            Ok(cmd) => {
                debug!("consume_command : received parsed command '{:?}'", cmd);
                match cmd {
                    DocumentListCommand::Add(name) => {
                        debug!("DocumentListCommand::Add {:?}", name);
                        let mut doc = Document::<T>::default();
                        doc.name = name.to_string();
                        self.push(doc);
                    }
                    DocumentListCommand::Remove(name) => {
                        unimplemented!();
                    }
                    DocumentListCommand::List => {
                        for doc in self.iter() {
                            println!("{:?}", doc);
                        }
                    }
                    DocumentListCommand::Show(name) => {
                        unimplemented!();
                    }
                }
                Ok(())
            }
            Err(err) => {
                error!("consume_command : {:?}", err);
                return Err(format!("{}", err));
            }
        }
    }

    fn consume_dsl_tree(&mut self, items: &Vec<DslTree>) -> Result<(), String> {
        debug!("consume_dsl_tree : items : '{:?}'", items);
        for item in items {
            match *item {
                DslTree::Scope(ref s, ref tree) => {
                    debug!("consume_dsl_tree : matching scope item '{:?}'", s);
                    match s {
                        _ => {
                            return Err(
                                "No scopes implemented for TranslationsDocumentList yet"
                                    .to_owned(),
                            );
                        }
                    }
                }
                DslTree::Command(ref s) => {
                    debug!("consume_dsl_tree command '{:?}'", s);
                    match self.consume_command(&s) {
                        Err(err) => {
                            return Err(err);
                        }
                        _ => {}
                    }
                }
                DslTree::Comment(ref s) => {
                    debug!("consume_dsl_tree comment '{:?}'", s);
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct I18NString {
    pub locale: String,
    pub key: String,
    pub value: String,
}

impl I18NString {
    pub fn new(s: String) -> I18NString {
        I18NString {
            locale: "en_US".to_owned(),
            key: "".to_owned(),
            value: s,
        }
    }
}

impl Default for I18NString {
    fn default() -> I18NString {
        I18NString {
            locale: "en_US".to_owned(),
            key: "-no-key-".to_owned(),
            value: "-no-value-".to_owned(),
        }
    }
}

impl I18NString {
    pub fn translate(&self, t: &TranslationDocument) -> Self {
        I18NString {
            locale: t.doc.locale.clone(),
            key: self.key.clone(),
            value: t.doc
                .items
                .get(&self.key)
                .unwrap_or(&I18NString::new("".to_owned()))
                .value
                .clone(),
        }
    }

    pub fn translate_self(&mut self, t: &TranslationDocument) -> () {
        match t.doc.items.get(&self.key) {
            Some(item) => {
                self.locale = item.locale.clone();
                self.value = item.value.clone();
            }
            None => {
                warn!(
                    "No translation found for '{:?}' in locale '{:?}'",
                    self.key,
                    t.doc.locale
                );
                self.locale = t.doc.locale.clone();
                self.value = "-no-value-".to_owned();
            }
        };

        debug!("Translated value is '{:?}'", self.value);
    }
}

pub trait Translatable {
    fn translate_in_place(&mut self, t: &TranslationDocument) -> ();
    fn translate(&self, t: &TranslationDocument) -> Self;
    fn all_i18n_strings(&self) -> Vec<&I18NString>;
}

//
// This struct only exists to make the top-level Model object serializable into a project's
// model.json
//

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct DocumentHeader {
    pub id: Uuid,
    pub name: String,
    pub doctype: String,
    pub doctype_version: i64,
    pub version: i64,
}

impl DocumentHeader {
    /// Return a string representation of the DocumentHeader
    ///
    pub fn to_string(&self) -> String {
        format!("document {}", self.id)
    }

    /// Return an indented JSON representation of the DocumentHeader
    ///
    /// partof: SPC-serialization-json
    pub fn to_json(&self) -> String {
        serde_json::to_string_pretty(&self).unwrap()
    }

    /// Return a compact JSON representation of the DocumentHeader
    ///
    /// partof: SPC-serialization-json
    pub fn to_json_compact(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }

    /// Initialize a DocumentHeader from a JSON string
    ///
    /// partof: SPC-serialization-json
    pub fn from_json(s: &str) -> Self {
        serde_json::from_str(s).unwrap()
    }

    /// Return a YAML representation of the DocumentHeader
    ///
    /// partof: #SPC-serialization-yaml
    pub fn to_yaml(&self) -> String {
        serde_yaml::to_string(&self).unwrap()
    }

    /// Initialize a DocumentHeader from a JSON string
    ///
    /// partof: SPC-serialization-yaml
    pub fn from_yaml(s: &str) -> Self {
        serde_yaml::from_str(s).unwrap()
    }
}
<commit_msg>feat: DocumentList remove command<commit_after>use serde;
use serde_json;
use serde_yaml;
use uuid::Uuid;

use structure::translation::TranslationDocument;
use dsl::command::{GearsDsl, DslTree, DslToken, DslTokens, command_grammar};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Document<T> {
    pub id: Uuid,
    pub name: String,
    pub doctype: String,
    pub doctype_version: i64,
    pub version: i64,
    pub doc: T,
}

pub type DocumentList<T> = Vec<Document<T>>;

impl<T> Document<T>
where
    T: serde::Serialize + serde::de::DeserializeOwned + Eq + Default,
{
    pub fn new_from_header(header: &DocumentHeader) -> Self {
        Self {
            id: header.id.clone(),
            name: header.name.clone(),
            doctype: header.doctype.clone(),
            doctype_version: header.doctype_version.clone(),
            version: header.version.clone(),
            doc: <T>::default(),
        }
    }

    pub fn get_header(&self) -> DocumentHeader {
        DocumentHeader {
            id: self.id.clone(),
            name: self.name.clone(),
            doctype: self.doctype.clone(),
            doctype_version: self.doctype_version.clone(),
            version: self.version.clone(),
        }
    }

    pub fn set_header(&mut self, header: &DocumentHeader) -> () {
        self.id = header.id.clone();
        self.name = header.name.clone();
        self.doctype = header.doctype.clone();
        self.doctype_version = header.doctype_version.clone();
        self.version = header.version.clone();
    }

    /// Return a string representation of the Document
    ///
    pub fn to_string(&self) -> String {
        format!("document {}", self.id)
    }

    /// Return a summary of the Document
    ///
    pub fn summary(&self) -> String {
        format!("Doc {:?} - {:?} - {:?}", self.doctype, self.id, self.name)
    }

    /// Return an indented JSON representation of the Document
    ///
    /// partof: SPC-serialization-json
    pub fn to_json(&self) -> String {
        serde_json::to_string_pretty(&self).unwrap()
    }

    /// Return a compact JSON representation of the Document
    ///
    /// partof: SPC-serialization-json
    pub fn to_json_compact(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }

    /// Initialize a Document from a JSON string
    ///
    /// partof: SPC-serialization-json
    pub fn from_json(s: &str) -> Self {
        serde_json::from_str(s).unwrap()
    }

    /// Return a YAML representation of the Document
    ///
    /// partof: #SPC-serialization-yaml
    pub fn to_yaml(&self) -> String {
        serde_yaml::to_string(&self).unwrap()
    }

    /// Initialize a Document from a JSON string
    ///
    /// partof: SPC-serialization-yaml
    pub fn from_yaml(s: &str) -> Self {
        serde_yaml::from_str(s).unwrap()
    }
}

impl<T> Default for Document<T>
where
    T: Default,
{
    fn default() -> Self {
        Self {
            id: Uuid::new_v4(),
            name: "default".to_owned(),
            doctype: "".to_owned(),
            doctype_version: 1,
            version: 1,
            doc: <T>::default(),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum DocumentListCommand {
    Add(String),
    Remove(String),
    List,
    Show(String),
}

impl DocumentListCommand {
    fn as_dsl_token(&self) -> DslToken {
        let s = match *self {
            DocumentListCommand::Add(ref e) => format!("add {}", e),
            DocumentListCommand::Remove(ref e) => format!("remove {}", e),
            DocumentListCommand::List => format!("list"),
            DocumentListCommand::Show(ref e) => format!("show {}", e),
        };
        DslToken::Command(s)
    }
}

use std::fmt::Debug;

impl<T> GearsDsl for DocumentList<T>
where
    T: Default + Debug,
{
    fn generate_dsl(&self) -> DslTokens {
        let mut res = DslTokens::new();

        for doc in self {
            res.push(DocumentListCommand::Add(doc.name.clone()).as_dsl_token());
        }

        res
    }

    fn consume_command(&mut self, s: &str) -> Result<(), String> {
        debug!("consume_command : received command string '{:?}'", s);
        match command_grammar::document_list_command(&s) {
            Ok(cmd) => {
                debug!("consume_command : received parsed command '{:?}'", cmd);
                match cmd {
                    DocumentListCommand::Add(name) => {
                        debug!("DocumentListCommand::Add {:?}", name);
                        let mut doc = Document::<T>::default();
                        doc.name = name.to_string();
                        self.push(doc);
                    }
                    DocumentListCommand::Remove(name) => {
                        self.retain({
                            |e| e.name.ne(&name)
                        });
                    }
                    DocumentListCommand::List => {
                        for doc in self.iter() {
                            println!("{:?}", doc);
                        }
                    }
                    DocumentListCommand::Show(name) => {
                        unimplemented!();
                    }
                }
                Ok(())
            }
            Err(err) => {
                error!("consume_command : {:?}", err);
                return Err(format!("{}", err));
            }
        }
    }

    fn consume_dsl_tree(&mut self, items: &Vec<DslTree>) -> Result<(), String> {
        debug!("consume_dsl_tree : items : '{:?}'", items);
        for item in items {
            match *item {
                DslTree::Scope(ref s, ref tree) => {
                    debug!("consume_dsl_tree : matching scope item '{:?}'", s);
                    match s {
                        _ => {
                            return Err(
                                "No scopes implemented for TranslationsDocumentList yet"
                                    .to_owned(),
                            );
                        }
                    }
                }
                DslTree::Command(ref s) => {
                    debug!("consume_dsl_tree command '{:?}'", s);
                    match self.consume_command(&s) {
                        Err(err) => {
                            return Err(err);
                        }
                        _ => {}
                    }
                }
                DslTree::Comment(ref s) => {
                    debug!("consume_dsl_tree comment '{:?}'", s);
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct I18NString {
    pub locale: String,
    pub key: String,
    pub value: String,
}

impl I18NString {
    pub fn new(s: String) -> I18NString {
        I18NString {
            locale: "en_US".to_owned(),
            key: "".to_owned(),
            value: s,
        }
    }
}

impl Default for I18NString {
    fn default() -> I18NString {
        I18NString {
            locale: "en_US".to_owned(),
            key: "-no-key-".to_owned(),
            value: "-no-value-".to_owned(),
        }
    }
}

impl I18NString {
    pub fn translate(&self, t: &TranslationDocument) -> Self {
        I18NString {
            locale: t.doc.locale.clone(),
            key: self.key.clone(),
            value: t.doc
                .items
                .get(&self.key)
                .unwrap_or(&I18NString::new("".to_owned()))
                .value
                .clone(),
        }
    }

    pub fn translate_self(&mut self, t: &TranslationDocument) -> () {
        match t.doc.items.get(&self.key) {
            Some(item) => {
                self.locale = item.locale.clone();
                self.value = item.value.clone();
            }
            None => {
                warn!(
                    "No translation found for '{:?}' in locale '{:?}'",
                    self.key,
                    t.doc.locale
                );
                self.locale = t.doc.locale.clone();
                self.value = "-no-value-".to_owned();
            }
        };

        debug!("Translated value is '{:?}'", self.value);
    }
}

pub trait Translatable {
    fn translate_in_place(&mut self, t: &TranslationDocument) -> ();
    fn translate(&self, t: &TranslationDocument) -> Self;
    fn all_i18n_strings(&self) -> Vec<&I18NString>;
}

//
// This struct only exists to make the top-level Model object serializable into a project's
// model.json
//

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct DocumentHeader {
    pub id: Uuid,
    pub name: String,
    pub doctype: String,
    pub doctype_version: i64,
    pub version: i64,
}

impl DocumentHeader {
    /// Return a string representation of the DocumentHeader
    ///
    pub fn to_string(&self) -> String {
        format!("document {}", self.id)
    }

    /// Return an indented JSON representation of the DocumentHeader
    ///
    /// partof: SPC-serialization-json
    pub fn to_json(&self) -> String {
        serde_json::to_string_pretty(&self).unwrap()
    }

    /// Return a compact JSON representation of the DocumentHeader
    ///
    /// partof: SPC-serialization-json
    pub fn to_json_compact(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }

    /// Initialize a DocumentHeader from a JSON string
    ///
    /// partof: SPC-serialization-json
    pub fn from_json(s: &str) -> Self {
        serde_json::from_str(s).unwrap()
    }

    /// Return a YAML representation of the DocumentHeader
    ///
    /// partof: #SPC-serialization-yaml
    pub fn to_yaml(&self) -> String {
        serde_yaml::to_string(&self).unwrap()
    }

    /// Initialize a DocumentHeader from a JSON string
    ///
    /// partof: SPC-serialization-yaml
    pub fn from_yaml(s: &str) -> Self {
        serde_yaml::from_str(s).unwrap()
    }
}
<|endoftext|>


<commit_before>//! The `info` subcommand, which shows meta-information about git-global.

use chrono::Duration;

use std::path::PathBuf;
use std::time::SystemTime;

use core::{GitGlobalConfig, GitGlobalResult, get_repos};
use errors::Result;

/// Get the age of the given file in terms of days, hours, minutes, and seconds.
fn get_age(filename: PathBuf) -> Option<String> {
    filename.metadata().ok()
        .and_then(|metadata| metadata.modified().ok())
        .and_then(|mtime| SystemTime::now().duration_since(mtime).ok())
        .and_then(|dur| Duration::from_std(dur).ok())
        .and_then(|dur| {
            let days = dur.num_days();
            let hours = dur.num_hours() - (days * 24);
            let mins = dur.num_minutes() - (days * 24 * 60) - (hours * 60);
            let secs =  dur.num_seconds() - (days * 24 * 60 * 60) -
                        (hours * 60 * 60) - (mins * 60);
            Some(format!("{}d, {}h, {}m, {}s", days, hours, mins, secs))
        })
}

pub fn get_results() -> Result<GitGlobalResult> {
    let repos = get_repos();
    let mut result = GitGlobalResult::new(&repos);
    let config = GitGlobalConfig::new();
    result.add_message(format!("git-global {}", crate_version!()));
    result.add_message(format!("=================="));
    result.add_message(format!("Number of repos: {}", repos.len()));
    result.add_message(format!("Base directory: {}", config.basedir));
    result.add_message(format!("Cache file: {}", config.cache_file.to_str().unwrap()));
    if let Some(age) = get_age(config.cache_file) {
        result.add_message(format!("Cache file age: {}", age));
    }
    result.add_message(format!("Ignored patterns:"));
    for pat in config.ignored_patterns.iter() {
        result.add_message(format!("  {}", pat));
    }
    Ok(result)
}
<commit_msg>Grow the underline for git global info based on version length<commit_after>//! The `info` subcommand, which shows meta-information about git-global.

use chrono::Duration;

use std::path::PathBuf;
use std::time::SystemTime;

use core::{GitGlobalConfig, GitGlobalResult, get_repos};
use errors::Result;

/// Get the age of the given file in terms of days, hours, minutes, and seconds.
fn get_age(filename: PathBuf) -> Option<String> {
    filename.metadata().ok()
        .and_then(|metadata| metadata.modified().ok())
        .and_then(|mtime| SystemTime::now().duration_since(mtime).ok())
        .and_then(|dur| Duration::from_std(dur).ok())
        .and_then(|dur| {
            let days = dur.num_days();
            let hours = dur.num_hours() - (days * 24);
            let mins = dur.num_minutes() - (days * 24 * 60) - (hours * 60);
            let secs =  dur.num_seconds() - (days * 24 * 60 * 60) -
                        (hours * 60 * 60) - (mins * 60);
            Some(format!("{}d, {}h, {}m, {}s", days, hours, mins, secs))
        })
}

pub fn get_results() -> Result<GitGlobalResult> {
    let repos = get_repos();
    let mut result = GitGlobalResult::new(&repos);
    let config = GitGlobalConfig::new();
    let version = format!("{}", crate_version!());
    // beginning of underline:   git-global x.x.x
    let mut underline = format!("===========");
    for _ in 0..version.len() {
        underline.push('=');
    }
    result.add_message(format!("git-global {}", version));
    result.add_message(underline);
    result.add_message(format!("Number of repos: {}", repos.len()));
    result.add_message(format!("Base directory: {}", config.basedir));
    result.add_message(format!("Cache file: {}", config.cache_file.to_str().unwrap()));
    if let Some(age) = get_age(config.cache_file) {
        result.add_message(format!("Cache file age: {}", age));
    }
    result.add_message(format!("Ignored patterns:"));
    for pat in config.ignored_patterns.iter() {
        result.add_message(format!("  {}", pat));
    }
    Ok(result)
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::mem;
use std::ptr;

use runtime::Messageable;

#[unsafe_no_drop_flag]
pub struct Id<T> {
	ptr: *T,
}

impl<T: Messageable> Id<T> {
	pub unsafe fn from_ptr(ptr: *T) -> Id<T> {
		msg_send![&*ptr retain];
		Id::from_retained_ptr(ptr)
	}

	pub unsafe fn from_retained_ptr(ptr: *T) -> Id<T> {
		Id { ptr: ptr }
	}
}

impl<T: Messageable> Clone for Id<T> {
	fn clone(&self) -> Id<T> {
		unsafe {
			Id::from_ptr(self.ptr)
		}
	}
}

#[unsafe_destructor]
impl<T: Messageable> Drop for Id<T> {
	fn drop(&mut self) {
		if !self.ptr.is_null() {
			let ptr = mem::replace(&mut self.ptr, ptr::null());
			unsafe {
				msg_send![&*ptr release];
			}
		}
	}
}

impl<T> Deref<T> for Id<T> {
	fn deref<'a>(&'a self) -> &'a T {
		unsafe { &*self.ptr }
	}
}

impl<T: PartialEq> PartialEq for Id<T> {
	fn eq(&self, other: &Id<T>) -> bool {
		self.deref() == other.deref()
	}

	fn ne(&self, other: &Id<T>) -> bool {
		self.deref() != other.deref()
	}
}

impl<T: Eq> Eq for Id<T> { }

impl<S: hash::Writer, T: hash::Hash<S>> hash::Hash<S> for Id<T> {
	fn hash(&self, state: &mut S) {
		self.deref().hash(state)
	}
}

impl<T: fmt::Show> fmt::Show for Id<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.deref().fmt(f)
	}
}

pub trait IdVector<T> {
	fn as_refs_slice<'a>(&'a self) -> &'a [&'a T];

	fn as_ptrs_slice<'a>(&'a self) -> &'a [*T] {
		unsafe {
			mem::transmute(self.as_refs_slice())
		}
	}
}

impl<T> IdVector<T> for Vec<Id<T>> {
	fn as_refs_slice<'a>(&'a self) -> &'a [&'a T] {
		unsafe {
			mem::transmute(self.as_slice())
		}
	}
}
<commit_msg>Implement IdVector for slices, too.<commit_after>use std::fmt;
use std::hash;
use std::mem;
use std::ptr;

use runtime::Messageable;

#[unsafe_no_drop_flag]
pub struct Id<T> {
	ptr: *T,
}

impl<T: Messageable> Id<T> {
	pub unsafe fn from_ptr(ptr: *T) -> Id<T> {
		msg_send![&*ptr retain];
		Id::from_retained_ptr(ptr)
	}

	pub unsafe fn from_retained_ptr(ptr: *T) -> Id<T> {
		Id { ptr: ptr }
	}
}

impl<T: Messageable> Clone for Id<T> {
	fn clone(&self) -> Id<T> {
		unsafe {
			Id::from_ptr(self.ptr)
		}
	}
}

#[unsafe_destructor]
impl<T: Messageable> Drop for Id<T> {
	fn drop(&mut self) {
		if !self.ptr.is_null() {
			let ptr = mem::replace(&mut self.ptr, ptr::null());
			unsafe {
				msg_send![&*ptr release];
			}
		}
	}
}

impl<T> Deref<T> for Id<T> {
	fn deref<'a>(&'a self) -> &'a T {
		unsafe { &*self.ptr }
	}
}

impl<T: PartialEq> PartialEq for Id<T> {
	fn eq(&self, other: &Id<T>) -> bool {
		self.deref() == other.deref()
	}

	fn ne(&self, other: &Id<T>) -> bool {
		self.deref() != other.deref()
	}
}

impl<T: Eq> Eq for Id<T> { }

impl<S: hash::Writer, T: hash::Hash<S>> hash::Hash<S> for Id<T> {
	fn hash(&self, state: &mut S) {
		self.deref().hash(state)
	}
}

impl<T: fmt::Show> fmt::Show for Id<T> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.deref().fmt(f)
	}
}

pub trait IdVector<T> {
	fn as_refs_slice<'a>(&'a self) -> &'a [&'a T];

	fn as_ptrs_slice<'a>(&'a self) -> &'a [*T] {
		unsafe {
			mem::transmute(self.as_refs_slice())
		}
	}
}

impl<T, V: Vector<Id<T>>> IdVector<T> for V {
	fn as_refs_slice<'a>(&'a self) -> &'a [&'a T] {
		unsafe {
			mem::transmute(self.as_slice())
		}
	}
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use ffipredict;

use std::ffi::{CString};
use libc::{c_char, c_double};
use std::default::Default;
use std::slice::bytes::copy_memory;
use std::mem::transmute;

pub struct Tle {
    pub name: String,
    pub line1: String,
    pub line2: String,
}

pub struct Location {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m: i32,
}

pub struct Predict {
    pub sat: ffipredict::sat_t,
    qth: ffipredict::qth_t,
}

fn create_tle_t(tle: Tle) -> Result<ffipredict::tle_t, &'static str> {
    let mut tle_t = ffipredict::tle_t {
        epoch: 0.0,
        epoch_year: 0,
        epoch_day: 0,
        epoch_fod: 0.0,
        xndt2o: 0.0,
        xndd6o: 0.0,
        bstar: 0.0,
        xincl: 0.0,
        xnodeo: 0.0,
        eo: 0.0,
        omegao: 0.0,
        xmo: 0.0,
        xno: 0.0,

        catnr: 0,
        elset: 0,
        revnum: 0,

        sat_name: [0; 25],
        idesg: [0; 9],
        status: ffipredict::op_stat_t::OP_STAT_UNKNOWN,

        xincl1: 0.0,
        xnodeo1: 0.0,
        omegao1: 0.0,
        //..Default::default()
    };

    let name = CString::new(tle.name).unwrap();
    let line1 = CString::new(tle.line1).unwrap();
    let line2 = CString::new(tle.line2).unwrap();
    let mut buf = [[0u8; 80]; 3];

    copy_memory(&mut buf[0], name.as_bytes_with_nul());
    copy_memory(&mut buf[1], line1.as_bytes_with_nul());
    copy_memory(&mut buf[2], line2.as_bytes_with_nul());

    let tle_set_result = unsafe { ffipredict::Get_Next_Tle_Set(transmute::<&u8, *const c_char>(&buf[0][0]), &mut tle_t)};

    if tle_set_result == 1 {
        Ok(tle_t)
    }
    else {
        Err("error in TLE parsing")
    }
}

impl Predict {

    pub fn new(tle: Tle, location: Location) -> Predict {
        let tle_t = create_tle_t(tle).unwrap();

        let sgps: ffipredict::sgpsdp_static_t = Default::default();
        let dps: ffipredict::deep_static_t = Default::default();
        let deep_arg: ffipredict::deep_arg_t = Default::default();
        let pos: ffipredict::vector_t = Default::default();
        let vel: ffipredict::vector_t = Default::default();

        let mut sat = ffipredict::sat_t{
            name: CString::new("").unwrap().as_ptr(),
            nickname: CString::new("").unwrap().as_ptr(),
            website: CString::new("").unwrap().as_ptr(),
            tle: tle_t,
            flags: 0,
            sgps: sgps,
            dps: dps,
            deep_arg: deep_arg,
            pos: pos,
            vel: vel,

            jul_epoch: 0.0,
            jul_utc: 0.0,
            tsince: 0.0,
            aos: 0.0,
            los: 0.0,
            az: 0.0,
            el: 0.0,
            range: 0.0,
            range_rate: 0.0,
            ra: 0.0,
            dec: 0.0,
            ssplat: 0.0,
            ssplon: 0.0,
            alt: 0.0,
            velo: 0.0,
            ma: 0.0,
            footprint: 0.0,
            phase: 0.0,
            meanmo: 0.0,
            orbit: 0,
            otype: ffipredict::orbit_type_t::ORBIT_TYPE_UNKNOWN,
            //..Default::default()
        };

        let mut qth = ffipredict::qth_t {
            name: CString::new("").unwrap().as_ptr(),
            loc: CString::new("").unwrap().as_ptr(),
            desc: CString::new("").unwrap().as_ptr(),
            lat: location.lat_deg,
            lon: location.lon_deg,
            alt: location.alt_m,
            qra: CString::new("").unwrap().as_ptr(),
            wx: CString::new("").unwrap().as_ptr(),
        };

        unsafe {ffipredict::select_ephemeris(&mut sat)};
        unsafe {ffipredict::gtk_sat_data_init_sat(&mut sat, &mut qth)};

        Predict{sat: sat, qth: qth}
    }

    pub fn update(&mut self) {
        let julian_time_now: c_double = unsafe {ffipredict::get_current_daynum()};
        unsafe {ffipredict::predict_calc(&mut self.sat, &mut self.qth, julian_time_now)};
        println!("az: {:.*}", 4, self.sat.az);
    }
}
<commit_msg>replace CStrings with statically allocated c strings<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use ffipredict;

use std::ffi::{CString};
use libc::{c_char, c_double};
use std::default::Default;
use std::slice::bytes::copy_memory;
use std::mem::transmute;

pub struct Tle {
    pub name: String,
    pub line1: String,
    pub line2: String,
}

pub struct Location {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m: i32,
}

pub struct Predict {
    pub sat: ffipredict::sat_t,
    qth: ffipredict::qth_t,
}

fn create_tle_t(tle: Tle) -> Result<ffipredict::tle_t, &'static str> {
    let mut tle_t = ffipredict::tle_t {
        epoch: 0.0,
        epoch_year: 0,
        epoch_day: 0,
        epoch_fod: 0.0,
        xndt2o: 0.0,
        xndd6o: 0.0,
        bstar: 0.0,
        xincl: 0.0,
        xnodeo: 0.0,
        eo: 0.0,
        omegao: 0.0,
        xmo: 0.0,
        xno: 0.0,

        catnr: 0,
        elset: 0,
        revnum: 0,

        sat_name: [0; 25],
        idesg: [0; 9],
        status: ffipredict::op_stat_t::OP_STAT_UNKNOWN,

        xincl1: 0.0,
        xnodeo1: 0.0,
        omegao1: 0.0,
        //..Default::default()
    };

    let name = CString::new(tle.name).unwrap();
    let line1 = CString::new(tle.line1).unwrap();
    let line2 = CString::new(tle.line2).unwrap();
    let mut buf = [[0u8; 80]; 3];

    copy_memory(&mut buf[0], name.as_bytes_with_nul());
    copy_memory(&mut buf[1], line1.as_bytes_with_nul());
    copy_memory(&mut buf[2], line2.as_bytes_with_nul());

    let tle_set_result = unsafe { ffipredict::Get_Next_Tle_Set(transmute::<&u8, *const c_char>(&buf[0][0]), &mut tle_t)};

    if tle_set_result == 1 {
        Ok(tle_t)
    }
    else {
        Err("error in TLE parsing")
    }
}

impl Predict {

    pub fn new(tle: Tle, location: Location) -> Predict {
        let tle_t = create_tle_t(tle).unwrap();

        let sgps: ffipredict::sgpsdp_static_t = Default::default();
        let dps: ffipredict::deep_static_t = Default::default();
        let deep_arg: ffipredict::deep_arg_t = Default::default();
        let pos: ffipredict::vector_t = Default::default();
        let vel: ffipredict::vector_t = Default::default();

        let mut sat = ffipredict::sat_t{
            name: b"placeholder\0".as_ptr() as *const i8,
            nickname: b"placeholder\0".as_ptr() as *const i8,
            website: b"placeholder\0".as_ptr() as *const i8,
            tle: tle_t,
            flags: 0,
            sgps: sgps,
            dps: dps,
            deep_arg: deep_arg,
            pos: pos,
            vel: vel,

            jul_epoch: 0.0,
            jul_utc: 0.0,
            tsince: 0.0,
            aos: 0.0,
            los: 0.0,
            az: 0.0,
            el: 0.0,
            range: 0.0,
            range_rate: 0.0,
            ra: 0.0,
            dec: 0.0,
            ssplat: 0.0,
            ssplon: 0.0,
            alt: 0.0,
            velo: 0.0,
            ma: 0.0,
            footprint: 0.0,
            phase: 0.0,
            meanmo: 0.0,
            orbit: 0,
            otype: ffipredict::orbit_type_t::ORBIT_TYPE_UNKNOWN,
            //..Default::default()
        };

        let mut qth = ffipredict::qth_t {
            name: b"placeholder\0".as_ptr() as *const i8,
            loc: b"placeholder\0".as_ptr() as *const i8,
            desc: b"placeholder\0".as_ptr() as *const i8,
            lat: location.lat_deg,
            lon: location.lon_deg,
            alt: location.alt_m,
            qra: b"placeholder\0".as_ptr() as *const i8,
            wx: b"placeholder\0".as_ptr() as *const i8,
        };

        unsafe {ffipredict::select_ephemeris(&mut sat)};
        unsafe {ffipredict::gtk_sat_data_init_sat(&mut sat, &mut qth)};

        Predict{sat: sat, qth: qth}
    }

    pub fn update(&mut self) {
        let julian_time_now: c_double = unsafe {ffipredict::get_current_daynum()};
        unsafe {ffipredict::predict_calc(&mut self.sat, &mut self.qth, julian_time_now)};
        println!("az: {:.*}", 4, self.sat.az);
    }
}
<|endoftext|>


<commit_before>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_addspaces() {
    assert addspaces( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

fn addspaces( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(addspaces(input))
}

enum Expression {
    Value(int),
    Symbol(~str),
    List(~[Expression])
    }

fn main() {
    let Blah:Expression = List(~[Value(1), List(~[Value(1), Symbol(~"xyz")])]);
    io::println( "(begin 1 2)" )
}
<commit_msg>Rename addspaces to pad_parentheses and add tests<commit_after>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

enum Expression {
    Value(int),
    Symbol(~str),
    List(~[Expression])
    }

fn main() {
    let Blah:Expression = List(~[Value(1), List(~[Value(1), Symbol(~"xyz")])]);
    io::println( "(begin 1 2)" )
}
<|endoftext|>


<commit_before>use frame::ChannelAssignment;

// Decode left and side channels to left and right channels.
//
// Two channels, left and side (difference) that transforms the difference
// into the right channel.
pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

/// Decode the current frame buffer
///
/// * `Independent` - does nothing to buffer because this channel assignment
///   is already correct.
/// * `LeftSide` - decode left and side channels to left and right channels.
/// * `RightSide` - decode side and right channels to left and right
///   channels.
/// * `MiddleSide` - decode midpoint and side channels to left and right
///   channels.
pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_middle_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_middle_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ -2, -14, 12, -6, 127, 13, -19, -6
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::MiddleSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<commit_msg>Add explanation for `decode_right_side`<commit_after>use frame::ChannelAssignment;

// Decode left and side channels to left and right channels.
//
// Two channels, left and side (difference) that transforms the difference
// into the right channel.
pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

// Decode side and right channels to left and right channels.
//
// Two channels, side (difference) and right that transforms the difference
// into the left channel.
pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

/// Decode the current frame buffer
///
/// * `Independent` - does nothing to buffer because this channel assignment
///   is already correct.
/// * `LeftSide` - decode left and side channels to left and right channels.
/// * `RightSide` - decode side and right channels to left and right
///   channels.
/// * `MiddleSide` - decode midpoint and side channels to left and right
///   channels.
pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_middle_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_middle_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ -2, -14, 12, -6, 127, 13, -19, -6
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::MiddleSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<|endoftext|>


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

use dom::bindings::callback::CallbackContainer;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding::CustomElementRegistryMethods;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding::ElementDefinitionOptions;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::domexception::{DOMErrorName, DOMException};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use html5ever::LocalName;
use js::conversions::ToJSValConvertible;
use js::jsapi::{IsConstructor, HandleObject, JS_GetProperty, JSAutoCompartment, JSContext};
use js::jsval::{JSVal, UndefinedValue};
use std::cell::Cell;
use std::collections::HashMap;
use std::rc::Rc;

/// https://html.spec.whatwg.org/multipage/#customelementregistry
#[dom_struct]
pub struct CustomElementRegistry {
    reflector_: Reflector,

    window: JS<Window>,

    #[ignore_heap_size_of = "Rc"]
    when_defined: DOMRefCell<HashMap<DOMString, Rc<Promise>>>,

    element_definition_is_running: Cell<bool>,

    #[ignore_heap_size_of = "Rc"]
    definitions: DOMRefCell<HashMap<DOMString, Rc<CustomElementDefinition>>>,
}

impl CustomElementRegistry {
    fn new_inherited(window: &Window) -> CustomElementRegistry {
        CustomElementRegistry {
            reflector_: Reflector::new(),
            window: JS::from_ref(window),
            when_defined: DOMRefCell::new(HashMap::new()),
            element_definition_is_running: Cell::new(false),
            definitions: DOMRefCell::new(HashMap::new()),
        }
    }

    pub fn new(window: &Window) -> Root<CustomElementRegistry> {
        reflect_dom_object(box CustomElementRegistry::new_inherited(window),
                           window,
                           CustomElementRegistryBinding::Wrap)
    }

    /// Cleans up any active promises
    /// https://github.com/servo/servo/issues/15318
    pub fn teardown(&self) {
        self.when_defined.borrow_mut().clear()
    }

    pub fn lookup_definition_by_constructor(&self, constructor: HandleObject) -> Option<Rc<CustomElementDefinition>> {
        self.definitions.borrow().values().find(|definition| {
            definition.constructor.callback() == constructor.get()
        }).cloned()
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
    /// Steps 10.1, 10.2
    #[allow(unsafe_code)]
    fn check_prototype(&self, constructor: HandleObject) -> ErrorResult {
        let global_scope = self.window.upcast::<GlobalScope>();
        rooted!(in(global_scope.get_cx()) let mut prototype = UndefinedValue());
        unsafe {
            // Step 10.1
            if !JS_GetProperty(global_scope.get_cx(),
                               constructor,
                               b"prototype\0".as_ptr() as *const _,
                               prototype.handle_mut()) {
                return Err(Error::JSFailed);
            }

            // Step 10.2
            if !prototype.is_object() {
                return Err(Error::Type("constructor.prototype is not an object".to_owned()));
            }
        }
        Ok(())
    }
}

impl CustomElementRegistryMethods for CustomElementRegistry {
    #[allow(unsafe_code, unrooted_must_root)]
    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
    fn Define(&self, name: DOMString, constructor_: Rc<Function>, options: &ElementDefinitionOptions) -> ErrorResult {
        let global_scope = self.window.upcast::<GlobalScope>();
        rooted!(in(global_scope.get_cx()) let constructor = constructor_.callback());

        // Step 1
        if unsafe { !IsConstructor(constructor.get()) } {
            return Err(Error::Type("Second argument of CustomElementRegistry.define is not a constructor".to_owned()));
        }

        // Step 2
        if !is_valid_custom_element_name(&name) {
            return Err(Error::Syntax)
        }

        // Step 3
        if self.definitions.borrow().contains_key(&name) {
            return Err(Error::NotSupported);
        }

        // Step 4
        if self.definitions.borrow().iter().any(|(_, ref def)| def.constructor == constructor_) {
            return Err(Error::NotSupported);
        }

        // Step 6
        let extends = &options.extends;

        // Steps 5, 7
        let local_name = if let Some(ref extended_name) = *extends {
            // Step 7.1
            if is_valid_custom_element_name(extended_name) {
                return Err(Error::NotSupported)
            }

            // Step 7.2
            if !is_known_element_interface(extended_name) {
                return Err(Error::NotSupported)
            }

            extended_name
        } else {
            // Step 7.3
            &name
        };

        // Step 8
        if self.element_definition_is_running.get() {
            return Err(Error::NotSupported);
        }

        // Step 9
        self.element_definition_is_running.set(true);

        // Steps 10.1 - 10.2
        let result = {
            let _ac = JSAutoCompartment::new(global_scope.get_cx(), constructor.get());
            self.check_prototype(constructor.handle())
        };

        // TODO: Steps 10.3 - 10.6
        // 10.3 - 10.4 Handle lifecycle callbacks
        // 10.5 - 10.6 Get observed attributes from the constructor

        self.element_definition_is_running.set(false);
        result?;

        // Step 11
        let definition = CustomElementDefinition::new(LocalName::from(&*name),
                                                      LocalName::from(&**local_name),
                                                      constructor_);

        // Step 12
        self.definitions.borrow_mut().insert(name.clone(), Rc::new(definition));

        // TODO: Step 13, 14, 15
        // Handle custom element upgrades

        // Step 16, 16.3
        if let Some(promise) = self.when_defined.borrow_mut().remove(&name) {
            // 16.1
            let cx = promise.global().get_cx();
            // 16.2
            promise.resolve_native(cx, &UndefinedValue());
        }
        Ok(())
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get
    #[allow(unsafe_code)]
    unsafe fn Get(&self, cx: *mut JSContext, name: DOMString) -> JSVal {
        match self.definitions.borrow().get(&name) {
            Some(definition) => {
                rooted!(in(cx) let mut constructor = UndefinedValue());
                definition.constructor.to_jsval(cx, constructor.handle_mut());
                constructor.get()
            },
            None => UndefinedValue(),
        }
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-whendefined
    #[allow(unrooted_must_root)]
    fn WhenDefined(&self, name: DOMString) -> Rc<Promise> {
        let global_scope = self.window.upcast::<GlobalScope>();

        // Step 1
        if !is_valid_custom_element_name(&name) {
            let promise = Promise::new(global_scope);
            promise.reject_native(global_scope.get_cx(), &DOMException::new(global_scope, DOMErrorName::SyntaxError));
            return promise
        }

        // Step 2
        if self.definitions.borrow().contains_key(&name) {
            let promise = Promise::new(global_scope);
            promise.resolve_native(global_scope.get_cx(), &UndefinedValue());
            return promise
        }

        // Step 3
        let mut map = self.when_defined.borrow_mut();

        // Steps 4, 5
        let promise = map.get(&name).cloned().unwrap_or_else(|| {
            let promise = Promise::new(global_scope);
            map.insert(name, promise.clone());
            promise
        });

        // Step 6
        promise
    }
}

/// https://html.spec.whatwg.org/multipage/#custom-element-definition
#[derive(HeapSizeOf, JSTraceable, Clone)]
pub struct CustomElementDefinition {
    pub name: LocalName,

    pub local_name: LocalName,

    #[ignore_heap_size_of = "Rc"]
    pub constructor: Rc<Function>,
}

impl CustomElementDefinition {
    fn new(name: LocalName, local_name: LocalName, constructor: Rc<Function>) -> CustomElementDefinition {
        CustomElementDefinition {
            name: name,
            local_name: local_name,
            constructor: constructor,
        }
    }

    /// https://html.spec.whatwg.org/multipage/#autonomous-custom-element
    pub fn is_autonomous(&self) -> bool {
        self.name == self.local_name
    }
}

/// https://html.spec.whatwg.org/multipage/#valid-custom-element-name
fn is_valid_custom_element_name(name: &str) -> bool {
    // Custom elment names must match:
    // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*

    let mut chars = name.chars();
    if !chars.next().map_or(false, |c| c >= 'a' && c <= 'z') {
        return false;
    }

    let mut has_dash = false;

    for c in chars {
        if c == '-' {
            has_dash = true;
            continue;
        }

        if !is_potential_custom_element_char(c) {
            return false;
        }
    }

    if !has_dash {
        return false;
    }

    if name == "annotation-xml" ||
        name == "color-profile" ||
        name == "font-face" ||
        name == "font-face-src" ||
        name == "font-face-uri" ||
        name == "font-face-format" ||
        name == "font-face-name" ||
        name == "missing-glyph"
    {
        return false;
    }

    true
}

/// Check if this character is a PCENChar
/// https://html.spec.whatwg.org/multipage/#prod-pcenchar
fn is_potential_custom_element_char(c: char) -> bool {
    c == '-' || c == '.' || c == '_' || c == '\u{B7}' ||
    (c >= '0' && c <= '9') ||
    (c >= 'a' && c <= 'z') ||
    (c >= '\u{C0}' && c <= '\u{D6}') ||
    (c >= '\u{D8}' && c <= '\u{F6}') ||
    (c >= '\u{F8}' && c <= '\u{37D}') ||
    (c >= '\u{37F}' && c <= '\u{1FFF}') ||
    (c >= '\u{200C}' && c <= '\u{200D}') ||
    (c >= '\u{203F}' && c <= '\u{2040}') ||
    (c >= '\u{2070}' && c <= '\u{2FEF}') ||
    (c >= '\u{3001}' && c <= '\u{D7FF}') ||
    (c >= '\u{F900}' && c <= '\u{FDCF}') ||
    (c >= '\u{FDF0}' && c <= '\u{FFFD}') ||
    (c >= '\u{10000}' && c <= '\u{EFFFF}')
}

fn is_known_element_interface(element: &str) -> bool {
    element == "a" ||
    element == "abbr" ||
    element == "acronym" ||
    element == "address" ||
    element == "applet" ||
    element == "area" ||
    element == "article" ||
    element == "aside" ||
    element == "audio" ||
    element == "b" ||
    element == "base" ||
    element == "bdi" ||
    element == "bdo" ||
    element == "big" ||
    element == "blockquote" ||
    element == "body" ||
    element == "br" ||
    element == "button" ||
    element == "canvas" ||
    element == "caption" ||
    element == "center" ||
    element == "cite" ||
    element == "code" ||
    element == "col" ||
    element == "colgroup" ||
    element == "data" ||
    element == "datalist" ||
    element == "dd" ||
    element == "del" ||
    element == "details" ||
    element == "dfn" ||
    element == "dialog" ||
    element == "dir" ||
    element == "div" ||
    element == "dl" ||
    element == "dt" ||
    element == "em" ||
    element == "embed" ||
    element == "fieldset" ||
    element == "figcaption" ||
    element == "figure" ||
    element == "font" ||
    element == "footer" ||
    element == "form" ||
    element == "frame" ||
    element == "frameset" ||
    element == "h1" ||
    element == "h2" ||
    element == "h3" ||
    element == "h4" ||
    element == "h5" ||
    element == "h6" ||
    element == "head" ||
    element == "header" ||
    element == "hgroup" ||
    element == "hr" ||
    element == "html" ||
    element == "i" ||
    element == "iframe" ||
    element == "img" ||
    element == "input" ||
    element == "ins" ||
    element == "kbd" ||
    element == "label" ||
    element == "legend" ||
    element == "li" ||
    element == "link" ||
    element == "listing" ||
    element == "main" ||
    element == "map" ||
    element == "mark" ||
    element == "marquee" ||
    element == "meta" ||
    element == "meter" ||
    element == "nav" ||
    element == "nobr" ||
    element == "noframes" ||
    element == "noscript" ||
    element == "object" ||
    element == "ol" ||
    element == "optgroup" ||
    element == "option" ||
    element == "output" ||
    element == "p" ||
    element == "param" ||
    element == "plaintext" ||
    element == "pre" ||
    element == "progress" ||
    element == "q" ||
    element == "rp" ||
    element == "rt" ||
    element == "ruby" ||
    element == "s" ||
    element == "samp" ||
    element == "script" ||
    element == "section" ||
    element == "select" ||
    element == "small" ||
    element == "source" ||
    element == "span" ||
    element == "strike" ||
    element == "strong" ||
    element == "style" ||
    element == "sub" ||
    element == "summary" ||
    element == "sup" ||
    element == "table" ||
    element == "tbody" ||
    element == "td" ||
    element == "template" ||
    element == "textarea" ||
    element == "tfoot" ||
    element == "th" ||
    element == "thead" ||
    element == "time" ||
    element == "title" ||
    element == "tr" ||
    element == "tt" ||
    element == "track" ||
    element == "u" ||
    element == "ul" ||
    element == "var" ||
    element == "video" ||
    element == "wbr" ||
    element == "xmp"
}
<commit_msg>Remove applet from list extendable interfaces<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::callback::CallbackContainer;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding::CustomElementRegistryMethods;
use dom::bindings::codegen::Bindings::CustomElementRegistryBinding::ElementDefinitionOptions;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::domexception::{DOMErrorName, DOMException};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use html5ever::LocalName;
use js::conversions::ToJSValConvertible;
use js::jsapi::{IsConstructor, HandleObject, JS_GetProperty, JSAutoCompartment, JSContext};
use js::jsval::{JSVal, UndefinedValue};
use std::cell::Cell;
use std::collections::HashMap;
use std::rc::Rc;

/// https://html.spec.whatwg.org/multipage/#customelementregistry
#[dom_struct]
pub struct CustomElementRegistry {
    reflector_: Reflector,

    window: JS<Window>,

    #[ignore_heap_size_of = "Rc"]
    when_defined: DOMRefCell<HashMap<DOMString, Rc<Promise>>>,

    element_definition_is_running: Cell<bool>,

    #[ignore_heap_size_of = "Rc"]
    definitions: DOMRefCell<HashMap<DOMString, Rc<CustomElementDefinition>>>,
}

impl CustomElementRegistry {
    fn new_inherited(window: &Window) -> CustomElementRegistry {
        CustomElementRegistry {
            reflector_: Reflector::new(),
            window: JS::from_ref(window),
            when_defined: DOMRefCell::new(HashMap::new()),
            element_definition_is_running: Cell::new(false),
            definitions: DOMRefCell::new(HashMap::new()),
        }
    }

    pub fn new(window: &Window) -> Root<CustomElementRegistry> {
        reflect_dom_object(box CustomElementRegistry::new_inherited(window),
                           window,
                           CustomElementRegistryBinding::Wrap)
    }

    /// Cleans up any active promises
    /// https://github.com/servo/servo/issues/15318
    pub fn teardown(&self) {
        self.when_defined.borrow_mut().clear()
    }

    pub fn lookup_definition_by_constructor(&self, constructor: HandleObject) -> Option<Rc<CustomElementDefinition>> {
        self.definitions.borrow().values().find(|definition| {
            definition.constructor.callback() == constructor.get()
        }).cloned()
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
    /// Steps 10.1, 10.2
    #[allow(unsafe_code)]
    fn check_prototype(&self, constructor: HandleObject) -> ErrorResult {
        let global_scope = self.window.upcast::<GlobalScope>();
        rooted!(in(global_scope.get_cx()) let mut prototype = UndefinedValue());
        unsafe {
            // Step 10.1
            if !JS_GetProperty(global_scope.get_cx(),
                               constructor,
                               b"prototype\0".as_ptr() as *const _,
                               prototype.handle_mut()) {
                return Err(Error::JSFailed);
            }

            // Step 10.2
            if !prototype.is_object() {
                return Err(Error::Type("constructor.prototype is not an object".to_owned()));
            }
        }
        Ok(())
    }
}

impl CustomElementRegistryMethods for CustomElementRegistry {
    #[allow(unsafe_code, unrooted_must_root)]
    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define
    fn Define(&self, name: DOMString, constructor_: Rc<Function>, options: &ElementDefinitionOptions) -> ErrorResult {
        let global_scope = self.window.upcast::<GlobalScope>();
        rooted!(in(global_scope.get_cx()) let constructor = constructor_.callback());

        // Step 1
        if unsafe { !IsConstructor(constructor.get()) } {
            return Err(Error::Type("Second argument of CustomElementRegistry.define is not a constructor".to_owned()));
        }

        // Step 2
        if !is_valid_custom_element_name(&name) {
            return Err(Error::Syntax)
        }

        // Step 3
        if self.definitions.borrow().contains_key(&name) {
            return Err(Error::NotSupported);
        }

        // Step 4
        if self.definitions.borrow().iter().any(|(_, ref def)| def.constructor == constructor_) {
            return Err(Error::NotSupported);
        }

        // Step 6
        let extends = &options.extends;

        // Steps 5, 7
        let local_name = if let Some(ref extended_name) = *extends {
            // Step 7.1
            if is_valid_custom_element_name(extended_name) {
                return Err(Error::NotSupported)
            }

            // Step 7.2
            if !is_extendable_element_interface(extended_name) {
                return Err(Error::NotSupported)
            }

            extended_name
        } else {
            // Step 7.3
            &name
        };

        // Step 8
        if self.element_definition_is_running.get() {
            return Err(Error::NotSupported);
        }

        // Step 9
        self.element_definition_is_running.set(true);

        // Steps 10.1 - 10.2
        let result = {
            let _ac = JSAutoCompartment::new(global_scope.get_cx(), constructor.get());
            self.check_prototype(constructor.handle())
        };

        // TODO: Steps 10.3 - 10.6
        // 10.3 - 10.4 Handle lifecycle callbacks
        // 10.5 - 10.6 Get observed attributes from the constructor

        self.element_definition_is_running.set(false);
        result?;

        // Step 11
        let definition = CustomElementDefinition::new(LocalName::from(&*name),
                                                      LocalName::from(&**local_name),
                                                      constructor_);

        // Step 12
        self.definitions.borrow_mut().insert(name.clone(), Rc::new(definition));

        // TODO: Step 13, 14, 15
        // Handle custom element upgrades

        // Step 16, 16.3
        if let Some(promise) = self.when_defined.borrow_mut().remove(&name) {
            // 16.1
            let cx = promise.global().get_cx();
            // 16.2
            promise.resolve_native(cx, &UndefinedValue());
        }
        Ok(())
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get
    #[allow(unsafe_code)]
    unsafe fn Get(&self, cx: *mut JSContext, name: DOMString) -> JSVal {
        match self.definitions.borrow().get(&name) {
            Some(definition) => {
                rooted!(in(cx) let mut constructor = UndefinedValue());
                definition.constructor.to_jsval(cx, constructor.handle_mut());
                constructor.get()
            },
            None => UndefinedValue(),
        }
    }

    /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-whendefined
    #[allow(unrooted_must_root)]
    fn WhenDefined(&self, name: DOMString) -> Rc<Promise> {
        let global_scope = self.window.upcast::<GlobalScope>();

        // Step 1
        if !is_valid_custom_element_name(&name) {
            let promise = Promise::new(global_scope);
            promise.reject_native(global_scope.get_cx(), &DOMException::new(global_scope, DOMErrorName::SyntaxError));
            return promise
        }

        // Step 2
        if self.definitions.borrow().contains_key(&name) {
            let promise = Promise::new(global_scope);
            promise.resolve_native(global_scope.get_cx(), &UndefinedValue());
            return promise
        }

        // Step 3
        let mut map = self.when_defined.borrow_mut();

        // Steps 4, 5
        let promise = map.get(&name).cloned().unwrap_or_else(|| {
            let promise = Promise::new(global_scope);
            map.insert(name, promise.clone());
            promise
        });

        // Step 6
        promise
    }
}

/// https://html.spec.whatwg.org/multipage/#custom-element-definition
#[derive(HeapSizeOf, JSTraceable, Clone)]
pub struct CustomElementDefinition {
    pub name: LocalName,

    pub local_name: LocalName,

    #[ignore_heap_size_of = "Rc"]
    pub constructor: Rc<Function>,
}

impl CustomElementDefinition {
    fn new(name: LocalName, local_name: LocalName, constructor: Rc<Function>) -> CustomElementDefinition {
        CustomElementDefinition {
            name: name,
            local_name: local_name,
            constructor: constructor,
        }
    }

    /// https://html.spec.whatwg.org/multipage/#autonomous-custom-element
    pub fn is_autonomous(&self) -> bool {
        self.name == self.local_name
    }
}

/// https://html.spec.whatwg.org/multipage/#valid-custom-element-name
fn is_valid_custom_element_name(name: &str) -> bool {
    // Custom elment names must match:
    // PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*

    let mut chars = name.chars();
    if !chars.next().map_or(false, |c| c >= 'a' && c <= 'z') {
        return false;
    }

    let mut has_dash = false;

    for c in chars {
        if c == '-' {
            has_dash = true;
            continue;
        }

        if !is_potential_custom_element_char(c) {
            return false;
        }
    }

    if !has_dash {
        return false;
    }

    if name == "annotation-xml" ||
        name == "color-profile" ||
        name == "font-face" ||
        name == "font-face-src" ||
        name == "font-face-uri" ||
        name == "font-face-format" ||
        name == "font-face-name" ||
        name == "missing-glyph"
    {
        return false;
    }

    true
}

/// Check if this character is a PCENChar
/// https://html.spec.whatwg.org/multipage/#prod-pcenchar
fn is_potential_custom_element_char(c: char) -> bool {
    c == '-' || c == '.' || c == '_' || c == '\u{B7}' ||
    (c >= '0' && c <= '9') ||
    (c >= 'a' && c <= 'z') ||
    (c >= '\u{C0}' && c <= '\u{D6}') ||
    (c >= '\u{D8}' && c <= '\u{F6}') ||
    (c >= '\u{F8}' && c <= '\u{37D}') ||
    (c >= '\u{37F}' && c <= '\u{1FFF}') ||
    (c >= '\u{200C}' && c <= '\u{200D}') ||
    (c >= '\u{203F}' && c <= '\u{2040}') ||
    (c >= '\u{2070}' && c <= '\u{2FEF}') ||
    (c >= '\u{3001}' && c <= '\u{D7FF}') ||
    (c >= '\u{F900}' && c <= '\u{FDCF}') ||
    (c >= '\u{FDF0}' && c <= '\u{FFFD}') ||
    (c >= '\u{10000}' && c <= '\u{EFFFF}')
}

fn is_extendable_element_interface(element: &str) -> bool {
    element == "a" ||
    element == "abbr" ||
    element == "acronym" ||
    element == "address" ||
    element == "area" ||
    element == "article" ||
    element == "aside" ||
    element == "audio" ||
    element == "b" ||
    element == "base" ||
    element == "bdi" ||
    element == "bdo" ||
    element == "big" ||
    element == "blockquote" ||
    element == "body" ||
    element == "br" ||
    element == "button" ||
    element == "canvas" ||
    element == "caption" ||
    element == "center" ||
    element == "cite" ||
    element == "code" ||
    element == "col" ||
    element == "colgroup" ||
    element == "data" ||
    element == "datalist" ||
    element == "dd" ||
    element == "del" ||
    element == "details" ||
    element == "dfn" ||
    element == "dialog" ||
    element == "dir" ||
    element == "div" ||
    element == "dl" ||
    element == "dt" ||
    element == "em" ||
    element == "embed" ||
    element == "fieldset" ||
    element == "figcaption" ||
    element == "figure" ||
    element == "font" ||
    element == "footer" ||
    element == "form" ||
    element == "frame" ||
    element == "frameset" ||
    element == "h1" ||
    element == "h2" ||
    element == "h3" ||
    element == "h4" ||
    element == "h5" ||
    element == "h6" ||
    element == "head" ||
    element == "header" ||
    element == "hgroup" ||
    element == "hr" ||
    element == "html" ||
    element == "i" ||
    element == "iframe" ||
    element == "img" ||
    element == "input" ||
    element == "ins" ||
    element == "kbd" ||
    element == "label" ||
    element == "legend" ||
    element == "li" ||
    element == "link" ||
    element == "listing" ||
    element == "main" ||
    element == "map" ||
    element == "mark" ||
    element == "marquee" ||
    element == "meta" ||
    element == "meter" ||
    element == "nav" ||
    element == "nobr" ||
    element == "noframes" ||
    element == "noscript" ||
    element == "object" ||
    element == "ol" ||
    element == "optgroup" ||
    element == "option" ||
    element == "output" ||
    element == "p" ||
    element == "param" ||
    element == "plaintext" ||
    element == "pre" ||
    element == "progress" ||
    element == "q" ||
    element == "rp" ||
    element == "rt" ||
    element == "ruby" ||
    element == "s" ||
    element == "samp" ||
    element == "script" ||
    element == "section" ||
    element == "select" ||
    element == "small" ||
    element == "source" ||
    element == "span" ||
    element == "strike" ||
    element == "strong" ||
    element == "style" ||
    element == "sub" ||
    element == "summary" ||
    element == "sup" ||
    element == "table" ||
    element == "tbody" ||
    element == "td" ||
    element == "template" ||
    element == "textarea" ||
    element == "tfoot" ||
    element == "th" ||
    element == "thead" ||
    element == "time" ||
    element == "title" ||
    element == "tr" ||
    element == "tt" ||
    element == "track" ||
    element == "u" ||
    element == "ul" ||
    element == "var" ||
    element == "video" ||
    element == "wbr" ||
    element == "xmp"
}
<|endoftext|>


<commit_before>//! Support for detecting `encoding_rs` encodings, with or without
//! `uchardet`.
//!
//! Note that we do _not_ promise to always return the same output for any
//! given input, even in stable versions of this API.  Our contract is that
//! we try to get the right answer.

#![warn(missing_docs)]

extern crate encoding_rs;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[cfg(feature="uchardet")]
extern crate uchardet;

use encoding_rs::Encoding;
use std::borrow::Cow;

pub use errors::*;
#[cfg(feature="uchardet")]
pub use uchardet_detector::*;

mod errors;
#[cfg(feature="uchardet")]
mod uchardet_detector;

/// How accurate was our decoding?
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Accuracy {
    /// We didn't need to replace any malformed sequences with replacement
    /// characters.
    Lossless,
    /// We needed to replace malformed sequences with replacement
    /// characters.
    Lossy,
}

impl Accuracy {
    /// Build an `Accuracy` from an `Encoding` decode result.
    fn from_decode_result(lossy: bool) -> Accuracy {
        if lossy {
            Accuracy::Lossy
        } else {
            Accuracy::Lossless
        }
    }
}

/// This trait is implemented by our various encoding detectors.
pub trait EncodingDetector {
    /// Detect the encoding of `data`, and return a matching
    /// `encoding_rs::Encoding` object if possible.  The `hint` value will
    /// be used as a default unless we're not reasonably sure what
    /// character set is used by `data.
    fn detect_encoding(data: &[u8], hint: &'static Encoding)
                       -> Result<&'static Encoding>;

    /// Decode `data` to UTF-8 bytes **which may not be fully valid UTF-8**
    /// in some cases.  This method should only be used if you need high
    /// performance.  If the input data looks like UTF-8, it will be
    /// returned without copying.
    ///
    /// Note that this should only be called on complete input data, not on
    /// chunks of streaming data.
    fn decode_as_utf8_bytes<'a>(data: &'a [u8], hint: &'static Encoding)
                            -> Result<(Cow<'a, [u8]>, Accuracy)>
    {
        let encoding: &Encoding = try!(Self::detect_encoding(data, hint));
        if encoding == encoding_rs::UTF_8 {
            // Our results might be invalid UTF-8 if we guessed the wrong
            // encoding, but they're lossless.
            Ok((Cow::Borrowed(data), Accuracy::Lossless))
        } else {
            let (decoded, _, lossy) = encoding.decode(data);
            Ok((Cow::Owned(decoded.into_bytes()),
                Accuracy::from_decode_result(lossy)))
        }
    }

    /// Decode `data` to a valid Rust UTF-8 string.  If the input data is
    /// valid UTF-8, it will be returned without copying.
    ///
    /// Note that this should only be called on complete input data, not on
    /// chunks of streaming data.
    fn decode<'a>(data: &'a [u8], hint: &'static Encoding)
              -> Result<(Cow<'a, str>, Accuracy)>
    {
        let encoding: &Encoding = try!(Self::detect_encoding(data, hint));
        if encoding == encoding_rs::UTF_8 {
            // Use Rust's built-in decoder, which can operate in place if
            // we have valid UTF-8.
            let decoded: Cow<_> = String::from_utf8_lossy(data);
            // If `from_utf8_lossy` borrows the input string, it means we
            // didn't have any invalid code sequences that needed to be
            // replaced.
            let accuracy = match decoded {
                Cow::Borrowed(_) => Accuracy::Lossless,
                Cow::Owned(_) => Accuracy::Lossy,
            };
            Ok((decoded, accuracy))
        } else {
            let (decoded, _, lossy) = encoding.decode(data);
            Ok((Cow::Owned(decoded), Accuracy::from_decode_result(lossy)))
        }
    }
}

/// This detector recognizes Unicode byte order marks (BOM) and handles
/// them appropriately, but otherwise assumes the input is in the character
/// set specified by the `hint` argument to the detection or decoding
/// function.
///
/// This is intended to be very fast, and to give good results on a mix of
/// UTF-8 and UTF-16 files if called with `Hint::Utf8`.
pub struct BomDetector;

impl EncodingDetector for BomDetector {
    fn detect_encoding(data: &[u8], hint: &'static Encoding)
                       -> Result<&'static Encoding> {
        Ok(Encoding::for_bom(data).unwrap_or(hint))
    }
}
<commit_msg>encodingdet: Update some comments<commit_after>//! Support for detecting `encoding_rs` encodings, with or without
//! `uchardet`.
//!
//! Note that we do _not_ promise to always return the same output for any
//! given input, even in stable versions of this API.  Our contract is that
//! we try to get the right answer.

#![warn(missing_docs)]

extern crate encoding_rs;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[cfg(feature="uchardet")]
extern crate uchardet;

use encoding_rs::Encoding;
use std::borrow::Cow;

pub use errors::*;
#[cfg(feature="uchardet")]
pub use uchardet_detector::*;

mod errors;
#[cfg(feature="uchardet")]
mod uchardet_detector;

/// How accurate was our decoding?
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Accuracy {
    /// We didn't need to replace any malformed sequences with replacement
    /// characters.
    Lossless,
    /// We needed to replace malformed sequences with replacement
    /// characters.
    Lossy,
}

impl Accuracy {
    /// Build an `Accuracy` from an `Encoding` decode result.
    fn from_decode_result(lossy: bool) -> Accuracy {
        if lossy {
            Accuracy::Lossy
        } else {
            Accuracy::Lossless
        }
    }
}

/// This trait is implemented by our various encoding detectors.
pub trait EncodingDetector {
    /// Detect the encoding of `data`, and return a matching
    /// `encoding_rs::Encoding` object if possible.  The `hint` value will
    /// be used as a default if we're not reasonably sure what character
    /// set is used by `data`.
    fn detect_encoding(data: &[u8], hint: &'static Encoding)
                       -> Result<&'static Encoding>;

    /// Decode `data` to UTF-8 bytes **which may not be fully valid UTF-8**
    /// in some cases.  This method should only be used if you need high
    /// performance.  If the input data looks like UTF-8, it will be
    /// returned without copying.
    ///
    /// Note that this should only be called on complete input data, not on
    /// chunks of streaming data.
    fn decode_as_utf8_bytes<'a>(data: &'a [u8], hint: &'static Encoding)
                            -> Result<(Cow<'a, [u8]>, Accuracy)>
    {
        let encoding: &Encoding = try!(Self::detect_encoding(data, hint));
        if encoding == encoding_rs::UTF_8 {
            // Our results might be invalid UTF-8 if we guessed the wrong
            // encoding, but they're lossless.
            Ok((Cow::Borrowed(data), Accuracy::Lossless))
        } else {
            let (decoded, _, lossy) = encoding.decode(data);
            Ok((Cow::Owned(decoded.into_bytes()),
                Accuracy::from_decode_result(lossy)))
        }
    }

    /// Decode `data` to a valid Rust UTF-8 string.  If the input data is
    /// valid UTF-8, it will be returned without copying.
    ///
    /// Note that this should only be called on complete input data, not on
    /// chunks of streaming data.
    fn decode<'a>(data: &'a [u8], hint: &'static Encoding)
              -> Result<(Cow<'a, str>, Accuracy)>
    {
        let encoding: &Encoding = try!(Self::detect_encoding(data, hint));
        if encoding == encoding_rs::UTF_8 {
            // Use Rust's built-in "decoder," which can operate in place if
            // we have valid UTF-8.
            let decoded: Cow<_> = String::from_utf8_lossy(data);
            // If `from_utf8_lossy` borrows the input string, it means we
            // didn't have any invalid code sequences that needed to be
            // replaced.
            let accuracy = match decoded {
                Cow::Borrowed(_) => Accuracy::Lossless,
                Cow::Owned(_) => Accuracy::Lossy,
            };
            Ok((decoded, accuracy))
        } else {
            let (decoded, _, lossy) = encoding.decode(data);
            Ok((Cow::Owned(decoded), Accuracy::from_decode_result(lossy)))
        }
    }
}

/// This detector recognizes Unicode byte order marks (BOM) and handles
/// them appropriately, but otherwise assumes the input is in the character
/// set specified by the `hint` argument to the detection or decoding
/// function.
///
/// This is intended to be very fast, and to give good results on a mix of
/// UTF-8 and UTF-16 files if called with `Hint::Utf8`.
pub struct BomDetector;

impl EncodingDetector for BomDetector {
    fn detect_encoding(data: &[u8], hint: &'static Encoding)
                       -> Result<&'static Encoding> {
        Ok(Encoding::for_bom(data).unwrap_or(hint))
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate enum_map;

use enum_map::{EnumMap, Internal, 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_option_bool() {
    let mut map = enum_map! { None => 1, Some(false) => 2, Some(true) => 3};
    assert_eq!(map[None], 1);
    assert_eq!(map[Some(false)], 2);
    assert_eq!(map[Some(true)], 3);
    map[None] = 4;
    map[Some(false)] = 5;
    map[Some(true)] = 6;
    assert_eq!(map[None], 4);
    assert_eq!(map[Some(false)], 5);
    assert_eq!(map[Some(true)], 6);
    assert_eq!(map.as_slice(), [4, 5, 6]);
    let expected = [(None, 4), (Some(false), 5), (Some(true), 6)];
    assert_eq!(map.into_iter().collect::<Vec<_>>(), expected);
}

#[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 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> Internal<V> for X {
    type Array = [V; 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());
}<commit_msg>Reformat code<commit_after>#[macro_use]
extern crate enum_map;

use enum_map::{EnumMap, Internal, 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_option_bool() {
    let mut map = enum_map! { None => 1, Some(false) => 2, Some(true) => 3};
    assert_eq!(map[None], 1);
    assert_eq!(map[Some(false)], 2);
    assert_eq!(map[Some(true)], 3);
    map[None] = 4;
    map[Some(false)] = 5;
    map[Some(true)] = 6;
    assert_eq!(map[None], 4);
    assert_eq!(map[Some(false)], 5);
    assert_eq!(map[Some(true)], 6);
    assert_eq!(map.as_slice(), [4, 5, 6]);
    let expected = [(None, 4), (Some(false), 5), (Some(true), 6)];
    assert_eq!(map.into_iter().collect::<Vec<_>>(), expected);
}

#[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 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> Internal<V> for X {
    type Array = [V; 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());
}
<|endoftext|>