<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use value::{sort_key_value_pairs, KeyValuePairs, Value};
use decor::{InternalString, Repr};
use key::Key;
use array_of_tables::ArrayOfTables;
use intrusive_collections::LinkedListLink;
use document::{DocumentInner, ROOT_HEADER};
use formatted::{decorate, to_key_value};

// TODO: add method to extract a child table into an inline table
// TODO: add non mutable API
// TODO: impl Index
// TODO: impl Debug
// TODO: documentation

/// Type representing a TOML non-inline table
pub struct Table {
    pub(crate) header: Header,
    pub(crate) key_value_pairs: KeyValuePairs,

    // Value in the map is a  pointer to a linked list node.
    // All nodes are allocated in the typed arena and,
    // therefore, won't relocate.
    // Linked list itself (head of the list) is stored in the Document.
    //
    // Using pointer here is safe, since none of the pointers
    // will outlive the document. Also, we can't use a reference to
    // a table while having a mut ref to its child (granted by brwchk).
    //
    // Note: pointers should be wrapped in NonZero,
    // but this API is nightly-only atm.
    tables: HashMap<InternalString, *mut Table>,
    arrays: HashMap<InternalString, ArrayOfTables>,

    // Intrusive pointers to next and previous table in the document
    pub(crate) link: LinkedListLink,
    // We need this pointer to support (sub)table insertion and deletion
    doc: *mut DocumentInner,
}

#[derive(Eq, PartialEq, Clone, Debug, Hash)]
pub(crate) struct Header {
    // ```notrust
    // # comment
    // [ a.  'escaped \n'.  c ]
    // ```
    //
    // Corresponds to `Repr("#comment\n", " a.  'escaped \\n'.  c ", "\n")`
    pub repr: Repr,
    pub kind: HeaderKind,
}

// # Example
//
// ```notrust
// [dependencies.serde]
// version = "1.0"
// [[bin]]
// name = "add"
// ```
//
// Header kind of `dependencies` is `Implicit`,
// header kind of `dependencies.serde` is `Standard`,
// header kind of `bin` is `Array`.
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
pub(crate) enum HeaderKind {
    Implicit,
    Standard,
    Array,
}

/// An immutable reference to the child
pub enum TableRef<'a> {
    /// A reference to the child value
    Value(&'a Value),
    /// A reference to the child table
    Table(&'a Table),
    /// A reference to the child array of tables
    Array(&'a ArrayOfTables),
}

/// Return type of table.entry("key")
pub enum TableEntry<'a> {
    /// A reference to the child value
    Value(&'a mut Value),
    /// A reference to the child table
    Table(&'a mut Table),
    /// A reference to the child array of tables
    Array(&'a mut ArrayOfTables),
    /// A reference to the table itself
    Vacant(&'a mut Table),
}

impl Table {
    pub(crate) fn new(header: Header, doc: *mut DocumentInner) -> Self {
        Self {
            header: header,
            doc: doc,
            key_value_pairs: Default::default(),
            tables: Default::default(),
            arrays: Default::default(),
            link: Default::default(),
        }
    }
    pub fn contains_key(&self, key: &str) -> bool {
        self.contains_value(key) || self.contains_array(key) || self.contains_table(key)
    }
    pub fn contains_value(&self, key: &str) -> bool {
        self.key_value_pairs.contains_key(key)
    }
    pub fn contains_table(&self, key: &str) -> bool {
        self.tables.contains_key(key)
    }
    pub fn contains_array(&self, key: &str) -> bool {
        self.arrays.contains_key(key)
    }

    // argh, impl trait please
    pub fn iter<'a>(&'a self) -> Box<Iterator<Item = (&'a str, TableRef<'a>)> + 'a> {
        Box::new(
            self.key_value_pairs
                .iter()
                .map(|(k, kv)| (&k[..], TableRef::Value(&kv.value)))
                .chain(
                    self.arrays
                        .iter()
                        .map(|(k, a)| (&k[..], TableRef::Array(a))),
                )
                .chain(
                    self.tables
                        .iter()
                        .map(|(k, ptr)| (&k[..], TableRef::Table(unsafe { &**ptr }))),
                ),
        )
    }

    pub fn remove(&mut self, key: &str) -> bool {
        self.remove_table(key) || self.remove_array(key) || self.remove_value(key).is_some()
    }

    pub fn remove_value<'a>(&'a mut self, key: &str) -> Option<Value> {
        self.key_value_pairs.remove(key).map(|kv| kv.value)
    }

    /// Sorts Key/Value Pairs of the table,
    /// doesn't affect subtables or subarrays.
    pub fn sort_values(&mut self) {
        sort_key_value_pairs(&mut self.key_value_pairs);
    }

    pub fn len(&self) -> usize {
        self.key_value_pairs.len() + self.tables.len() + self.arrays.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn entry<'a>(&'a mut self, key: &str) -> TableEntry<'a> {
        if !self.contains_key(key) {
            TableEntry::Vacant(self)
        } else if let Some(table) = self.tables.get_mut(key) {
            TableEntry::Table(
                // safe, all child pointers are valid
                unsafe { table.as_mut().unwrap() },
            )
        } else if let Some(kv) = self.key_value_pairs.get_mut(key) {
            TableEntry::Value(&mut kv.value)
        } else {
            // argh, non-lexical lifetimes please
            TableEntry::Array(self.arrays.get_mut(key).unwrap())
        }
    }

    pub fn append_value<V: Into<Value>>(&mut self, key: Key, value: V) -> TableEntry {
        match self.entry(key.get()) {
            TableEntry::Vacant(me) => {
                TableEntry::Value(me.insert_value_assume_vacant(key, value.into()))
            }
            otherwise => otherwise,
        }
    }

    /// Tries to remove the table with the given key,
    /// returns true if this operation succeeds, false otherwise.
    pub fn remove_table<'a>(&'a mut self, key: &str) -> bool {
        match self.tables.entry(key.into()) {
            Entry::Vacant(..) => false,
            Entry::Occupied(e) => {
                // safe, doc pointer is always valid
                remove_table_recursive(*e.get(), unsafe { self.doc.as_mut().unwrap() });
                e.remove();
                true
            }
        }
    }

    /// Tries to insert a new table after the last table's child or,
    /// if the table has no children, after the table itself.
    /// If a child with the given key is present, returns a reference
    /// to this child.
    pub fn insert_table(&mut self, key: Key) -> TableEntry {
        let after_ptr = self.tables
            .values()
            .last()
            .map(|p| *p as *const Table)
            .unwrap_or(self as *const Table);
        let header = self.child_header(key.raw(), HeaderKind::Standard);
        self.insert_table_with_header(key.get(), header, after_ptr)
    }

    pub fn append_table(&mut self, key: Key) -> TableEntry {
        let header = self.child_header(key.raw(), HeaderKind::Standard);
        self.append_table_with_header(key.get(), header)
    }

    pub fn remove_array<'a>(&'a mut self, key: &str) -> bool {
        self.arrays
            .remove(key)
            .map(|mut a| a.remove_all())
            .is_some()
    }

    pub fn insert_array(&mut self, key: Key) -> TableEntry {
        let child_key = self.child_key(key.raw());
        match self.entry(key.get()) {
            TableEntry::Vacant(me) => TableEntry::Array(me.insert_array_assume_vacant(&child_key)),
            otherwise => otherwise,
        }
    }

    /// # Examples
    ///
    /// ```notrust
    /// [target."x86_64/windows.json".dependencies]
    /// ```
    ///
    /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit.
    ///
    /// ```
    /// # extern crate toml_edit;
    /// # use toml_edit::Document;
    /// #
    /// # fn main() {
    /// let mut doc = "[a]\n[a.b]".parse::<Document>().unwrap();
    /// assert!(doc.root_mut().entry("a").as_table_mut().unwrap().set_implicit());
    /// assert_eq!(doc.to_string(), "[a.b]");
    /// # }
    /// ```
    pub fn set_implicit(&mut self) -> bool {
        if self.key_value_pairs.is_empty() && self.header.kind == HeaderKind::Standard {
            self.header.kind = HeaderKind::Implicit;
            true
        } else {
            false
        }
    }

    fn insert_value_assume_vacant(&mut self, key: Key, value: Value) -> &mut Value {
        debug_assert!(!self.tables.contains_key(key.get()));
        debug_assert!(!self.arrays.contains_key(key.get()));
        let mut kv = to_key_value(key.raw(), value);
        decorate(&mut kv.value, " ", "\n");
        &mut self.key_value_pairs.entry(key.into()).or_insert(kv).value
    }

    pub(crate) fn insert_array_assume_vacant<'a>(&'a mut self, key: &str) -> &'a mut ArrayOfTables {
        let doc = self.doc;
        self.arrays
            .entry(InternalString::from(key))
            .or_insert_with(|| ArrayOfTables::new(key, doc))
    }

    pub(crate) fn move_to_end(&mut self) {
        let doc: &mut DocumentInner = unsafe { self.doc.as_mut().unwrap() };
        doc.move_to_end(self);
    }

    pub(crate) fn child_header(&self, key: &str, kind: HeaderKind) -> Header {
        let child_key = self.child_key(key);
        Header {
            repr: Repr::new("\n", &child_key, "\n"),
            kind: kind,
        }
    }

    pub(crate) fn child_key(&self, key: &str) -> InternalString {
        let prefix = &self.header.repr.raw_value;
        if prefix == ROOT_HEADER {
            key.into()
        } else {
            format!("{}.{}", prefix, key)
        }
    }

    pub(crate) fn append_table_with_header<'a>(
        &'a mut self,
        key: &str,
        header: Header,
    ) -> TableEntry<'a> {
        let doc = unsafe { self.doc.as_ref().unwrap() };
        let back = doc.list.back().get().unwrap();
        self.insert_table_with_header(key, header, back)
    }

    pub(crate) fn insert_table_with_header<'a>(
        &'a mut self,
        key: &str,
        header: Header,
        after_ptr: *const Table,
    ) -> TableEntry<'a> {
        let doc = self.doc;
        match self.entry(key) {
            TableEntry::Vacant(me) => {
                let table = Table::new(header, me.doc);
                // safe, doc pointer is always valid
                let doc: &mut DocumentInner = unsafe { doc.as_mut().unwrap() };
                // insert into the document
                let node_ptr = doc.insert(table, after_ptr);
                // insert into the table
                let result = me.tables.insert(key.into(), node_ptr);
                debug_assert!(result.is_none());
                // safe, because we're borrowing self mutably
                TableEntry::Table(unsafe { node_ptr.as_mut().unwrap() })
            }
            otherwise => otherwise,
        }
    }
}

// TODO: This should be generated by macro or derive
/// Downcasting
impl<'a> TableEntry<'a> {
    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
        match *self {
            TableEntry::Table(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_array_mut(&mut self) -> Option<&mut ArrayOfTables> {
        match *self {
            TableEntry::Array(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_value_mut(&mut self) -> Option<&mut Value> {
        match *self {
            TableEntry::Value(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_vacant_mut(&mut self) -> Option<&mut Table> {
        match *self {
            TableEntry::Vacant(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_table(&self) -> Option<&Table> {
        match *self {
            TableEntry::Table(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_array(&self) -> Option<&ArrayOfTables> {
        match *self {
            TableEntry::Array(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_value(&self) -> Option<&Value> {
        match *self {
            TableEntry::Value(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_vacant(&self) -> Option<&Table> {
        match *self {
            TableEntry::Vacant(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn is_table(&self) -> bool {
        self.as_table().is_some()
    }
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }
    pub fn is_value(&self) -> bool {
        self.as_value().is_some()
    }
    pub fn is_vacant(&self) -> bool {
        self.as_vacant().is_some()
    }
}

pub(crate) fn remove_table_recursive(ptr: *mut Table, doc: &mut DocumentInner) {
    // safe, all child pointers are valid
    let child: &mut Table = unsafe { ptr.as_mut().unwrap() };
    let keys: Vec<InternalString> = child.tables.keys().cloned().collect();
    // recursive subtables removal
    for key in keys {
        child.remove_table(&key);
    }
    let keys: Vec<InternalString> = child.arrays.keys().cloned().collect();
    // recursive subarrays removal
    for key in keys {
        child.remove_array(&key);
    }
    // remove from the list
    doc.remove(ptr);
}
<commit_msg>feat(table): add append from inline table<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use value::{sort_key_value_pairs, InlineTable, KeyValuePairs, Value};
use decor::{InternalString, Repr};
use key::Key;
use array_of_tables::ArrayOfTables;
use intrusive_collections::LinkedListLink;
use document::{DocumentInner, ROOT_HEADER};
use formatted::{decorate, to_key_value};

// TODO: add method to extract a child table into an inline table
// TODO: add non mutable API
// TODO: impl Index
// TODO: impl Debug
// TODO: documentation

/// Type representing a TOML non-inline table
pub struct Table {
    pub(crate) header: Header,
    pub(crate) key_value_pairs: KeyValuePairs,

    // Value in the map is a  pointer to a linked list node.
    // All nodes are allocated in the typed arena and,
    // therefore, won't relocate.
    // Linked list itself (head of the list) is stored in the Document.
    //
    // Using pointer here is safe, since none of the pointers
    // will outlive the document. Also, we can't use a reference to
    // a table while having a mut ref to its child (granted by brwchk).
    //
    // Note: pointers should be wrapped in NonZero,
    // but this API is nightly-only atm.
    tables: HashMap<InternalString, *mut Table>,
    arrays: HashMap<InternalString, ArrayOfTables>,

    // Intrusive pointers to next and previous table in the document
    pub(crate) link: LinkedListLink,
    // We need this pointer to support (sub)table insertion and deletion
    doc: *mut DocumentInner,
}

#[derive(Eq, PartialEq, Clone, Debug, Hash)]
pub(crate) struct Header {
    // ```notrust
    // # comment
    // [ a.  'escaped \n'.  c ]
    // ```
    //
    // Corresponds to `Repr("#comment\n", " a.  'escaped \\n'.  c ", "\n")`
    pub repr: Repr,
    pub kind: HeaderKind,
}

// # Example
//
// ```notrust
// [dependencies.serde]
// version = "1.0"
// [[bin]]
// name = "add"
// ```
//
// Header kind of `dependencies` is `Implicit`,
// header kind of `dependencies.serde` is `Standard`,
// header kind of `bin` is `Array`.
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
pub(crate) enum HeaderKind {
    Implicit,
    Standard,
    Array,
}

/// An immutable reference to the child
pub enum TableRef<'a> {
    /// A reference to the child value
    Value(&'a Value),
    /// A reference to the child table
    Table(&'a Table),
    /// A reference to the child array of tables
    Array(&'a ArrayOfTables),
}

/// Return type of table.entry("key")
pub enum TableEntry<'a> {
    /// A reference to the child value
    Value(&'a mut Value),
    /// A reference to the child table
    Table(&'a mut Table),
    /// A reference to the child array of tables
    Array(&'a mut ArrayOfTables),
    /// A reference to the table itself
    Vacant(&'a mut Table),
}

impl Table {
    pub(crate) fn new(header: Header, doc: *mut DocumentInner) -> Self {
        Self {
            header: header,
            doc: doc,
            key_value_pairs: Default::default(),
            tables: Default::default(),
            arrays: Default::default(),
            link: Default::default(),
        }
    }
    pub fn contains_key(&self, key: &str) -> bool {
        self.contains_value(key) || self.contains_array(key) || self.contains_table(key)
    }
    pub fn contains_value(&self, key: &str) -> bool {
        self.key_value_pairs.contains_key(key)
    }
    pub fn contains_table(&self, key: &str) -> bool {
        self.tables.contains_key(key)
    }
    pub fn contains_array(&self, key: &str) -> bool {
        self.arrays.contains_key(key)
    }

    // argh, impl trait please
    pub fn iter<'a>(&'a self) -> Box<Iterator<Item = (&'a str, TableRef<'a>)> + 'a> {
        Box::new(
            self.key_value_pairs
                .iter()
                .map(|(k, kv)| (&k[..], TableRef::Value(&kv.value)))
                .chain(
                    self.arrays
                        .iter()
                        .map(|(k, a)| (&k[..], TableRef::Array(a))),
                )
                .chain(
                    self.tables
                        .iter()
                        .map(|(k, ptr)| (&k[..], TableRef::Table(unsafe { &**ptr }))),
                ),
        )
    }

    pub fn append(&mut self, other: &mut InlineTable) {
        while let Some((k, kv)) = other.key_value_pairs.pop_front() {
            self.key_value_pairs.insert(k, kv);
        }
    }

    pub fn remove(&mut self, key: &str) -> bool {
        self.remove_table(key) || self.remove_array(key) || self.remove_value(key).is_some()
    }

    pub fn remove_value<'a>(&'a mut self, key: &str) -> Option<Value> {
        self.key_value_pairs.remove(key).map(|kv| kv.value)
    }

    /// Sorts Key/Value Pairs of the table,
    /// doesn't affect subtables or subarrays.
    pub fn sort_values(&mut self) {
        sort_key_value_pairs(&mut self.key_value_pairs);
    }

    pub fn len(&self) -> usize {
        self.key_value_pairs.len() + self.tables.len() + self.arrays.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn entry<'a>(&'a mut self, key: &str) -> TableEntry<'a> {
        if !self.contains_key(key) {
            TableEntry::Vacant(self)
        } else if let Some(table) = self.tables.get_mut(key) {
            TableEntry::Table(
                // safe, all child pointers are valid
                unsafe { table.as_mut().unwrap() },
            )
        } else if let Some(kv) = self.key_value_pairs.get_mut(key) {
            TableEntry::Value(&mut kv.value)
        } else {
            // argh, non-lexical lifetimes please
            TableEntry::Array(self.arrays.get_mut(key).unwrap())
        }
    }

    pub fn append_value<V: Into<Value>>(&mut self, key: Key, value: V) -> TableEntry {
        match self.entry(key.get()) {
            TableEntry::Vacant(me) => {
                TableEntry::Value(me.insert_value_assume_vacant(key, value.into()))
            }
            otherwise => otherwise,
        }
    }

    /// Tries to remove the table with the given key,
    /// returns true if this operation succeeds, false otherwise.
    pub fn remove_table<'a>(&'a mut self, key: &str) -> bool {
        match self.tables.entry(key.into()) {
            Entry::Vacant(..) => false,
            Entry::Occupied(e) => {
                // safe, doc pointer is always valid
                remove_table_recursive(*e.get(), unsafe { self.doc.as_mut().unwrap() });
                e.remove();
                true
            }
        }
    }

    /// Tries to insert a new table after the last table's child or,
    /// if the table has no children, after the table itself.
    /// If a child with the given key is present, returns a reference
    /// to this child.
    pub fn insert_table(&mut self, key: Key) -> TableEntry {
        let after_ptr = self.tables
            .values()
            .last()
            .map(|p| *p as *const Table)
            .unwrap_or(self as *const Table);
        let header = self.child_header(key.raw(), HeaderKind::Standard);
        self.insert_table_with_header(key.get(), header, after_ptr)
    }

    pub fn append_table(&mut self, key: Key) -> TableEntry {
        let header = self.child_header(key.raw(), HeaderKind::Standard);
        self.append_table_with_header(key.get(), header)
    }

    pub fn remove_array<'a>(&'a mut self, key: &str) -> bool {
        self.arrays
            .remove(key)
            .map(|mut a| a.remove_all())
            .is_some()
    }

    pub fn insert_array(&mut self, key: Key) -> TableEntry {
        let child_key = self.child_key(key.raw());
        match self.entry(key.get()) {
            TableEntry::Vacant(me) => TableEntry::Array(me.insert_array_assume_vacant(&child_key)),
            otherwise => otherwise,
        }
    }

    /// # Examples
    ///
    /// ```notrust
    /// [target."x86_64/windows.json".dependencies]
    /// ```
    ///
    /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit.
    ///
    /// ```
    /// # extern crate toml_edit;
    /// # use toml_edit::Document;
    /// #
    /// # fn main() {
    /// let mut doc = "[a]\n[a.b]".parse::<Document>().unwrap();
    /// assert!(doc.root_mut().entry("a").as_table_mut().unwrap().set_implicit());
    /// assert_eq!(doc.to_string(), "[a.b]");
    /// # }
    /// ```
    pub fn set_implicit(&mut self) -> bool {
        if self.key_value_pairs.is_empty() && self.header.kind == HeaderKind::Standard {
            self.header.kind = HeaderKind::Implicit;
            true
        } else {
            false
        }
    }

    fn insert_value_assume_vacant(&mut self, key: Key, value: Value) -> &mut Value {
        debug_assert!(!self.tables.contains_key(key.get()));
        debug_assert!(!self.arrays.contains_key(key.get()));
        let mut kv = to_key_value(key.raw(), value);
        decorate(&mut kv.value, " ", "\n");
        &mut self.key_value_pairs.entry(key.into()).or_insert(kv).value
    }

    pub(crate) fn insert_array_assume_vacant<'a>(&'a mut self, key: &str) -> &'a mut ArrayOfTables {
        let doc = self.doc;
        self.arrays
            .entry(InternalString::from(key))
            .or_insert_with(|| ArrayOfTables::new(key, doc))
    }

    pub(crate) fn move_to_end(&mut self) {
        let doc: &mut DocumentInner = unsafe { self.doc.as_mut().unwrap() };
        doc.move_to_end(self);
    }

    pub(crate) fn child_header(&self, key: &str, kind: HeaderKind) -> Header {
        let child_key = self.child_key(key);
        Header {
            repr: Repr::new("\n", &child_key, "\n"),
            kind: kind,
        }
    }

    pub(crate) fn child_key(&self, key: &str) -> InternalString {
        let prefix = &self.header.repr.raw_value;
        if prefix == ROOT_HEADER {
            key.into()
        } else {
            format!("{}.{}", prefix, key)
        }
    }

    pub(crate) fn append_table_with_header<'a>(
        &'a mut self,
        key: &str,
        header: Header,
    ) -> TableEntry<'a> {
        let doc = unsafe { self.doc.as_ref().unwrap() };
        let back = doc.list.back().get().unwrap();
        self.insert_table_with_header(key, header, back)
    }

    pub(crate) fn insert_table_with_header<'a>(
        &'a mut self,
        key: &str,
        header: Header,
        after_ptr: *const Table,
    ) -> TableEntry<'a> {
        let doc = self.doc;
        match self.entry(key) {
            TableEntry::Vacant(me) => {
                let table = Table::new(header, me.doc);
                // safe, doc pointer is always valid
                let doc: &mut DocumentInner = unsafe { doc.as_mut().unwrap() };
                // insert into the document
                let node_ptr = doc.insert(table, after_ptr);
                // insert into the table
                let result = me.tables.insert(key.into(), node_ptr);
                debug_assert!(result.is_none());
                // safe, because we're borrowing self mutably
                TableEntry::Table(unsafe { node_ptr.as_mut().unwrap() })
            }
            otherwise => otherwise,
        }
    }
}

// TODO: This should be generated by macro or derive
/// Downcasting
impl<'a> TableEntry<'a> {
    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
        match *self {
            TableEntry::Table(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_array_mut(&mut self) -> Option<&mut ArrayOfTables> {
        match *self {
            TableEntry::Array(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_value_mut(&mut self) -> Option<&mut Value> {
        match *self {
            TableEntry::Value(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_vacant_mut(&mut self) -> Option<&mut Table> {
        match *self {
            TableEntry::Vacant(ref mut me) => Some(me),
            _ => None,
        }
    }
    pub fn as_table(&self) -> Option<&Table> {
        match *self {
            TableEntry::Table(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_array(&self) -> Option<&ArrayOfTables> {
        match *self {
            TableEntry::Array(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_value(&self) -> Option<&Value> {
        match *self {
            TableEntry::Value(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn as_vacant(&self) -> Option<&Table> {
        match *self {
            TableEntry::Vacant(ref me) => Some(me),
            _ => None,
        }
    }
    pub fn is_table(&self) -> bool {
        self.as_table().is_some()
    }
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }
    pub fn is_value(&self) -> bool {
        self.as_value().is_some()
    }
    pub fn is_vacant(&self) -> bool {
        self.as_vacant().is_some()
    }
}

pub(crate) fn remove_table_recursive(ptr: *mut Table, doc: &mut DocumentInner) {
    // safe, all child pointers are valid
    let child: &mut Table = unsafe { ptr.as_mut().unwrap() };
    let keys: Vec<InternalString> = child.tables.keys().cloned().collect();
    // recursive subtables removal
    for key in keys {
        child.remove_table(&key);
    }
    let keys: Vec<InternalString> = child.arrays.keys().cloned().collect();
    // recursive subarrays removal
    for key in keys {
        child.remove_array(&key);
    }
    // remove from the list
    doc.remove(ptr);
}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<Option<T>>,
}

impl<T> Level<T> {
    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<T>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level<T> {
    type Output= Option<T>;

    fn index(&self, vec: Vec2<usize>) -> &Option<T>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level<Tile>) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level<Tile>, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor(_)) = level[coord] {
            paths += 1;
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<commit_msg>got rid of tabs from level hopefully<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<Option<T>>,
}

impl<T> Level<T> {
    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<T>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level<T> {
    type Output= Option<T>;

    fn index(&self, vec: Vec2<usize>) -> &Option<T>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level<Tile>) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(ref n) = level[(x,y)] {
                if let &Tile::Floor = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall;
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level<Tile>, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(Tile::Floor(_)) = level[coord] {
            paths += 1;
        }
    }
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::fs;

use clap::{self, SubCommand};
use cargo::CargoResult;
use cargo::core::Workspace;
use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages,
                 VersionControl};
use cargo::util::paths;
use cargo::util::important_paths::find_root_manifest_for_wd;

pub use clap::{AppSettings, Arg, ArgMatches};
pub use cargo::{CliError, CliResult, Config};

pub type App = clap::App<'static, 'static>;

pub trait AppExt: Sized {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self;

    fn arg_package_spec(
        self,
        package: &'static str,
        all: &'static str,
        exclude: &'static str,
    ) -> Self {
        self.arg_package_spec_simple(package)
            ._arg(opt("all", all))
            ._arg(multi_opt("exclude", "SPEC", exclude))
    }

    fn arg_package_spec_simple(self, package: &'static str) -> Self {
        self._arg(multi_opt("package", "SPEC", package).short("p"))
    }

    fn arg_package(self, package: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC"))
    }

    fn arg_jobs(self) -> Self {
        self._arg(
            opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
                .short("j")
                .value_name("N"),
        )
    }

    fn arg_targets_all(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
        examle: &'static str,
        examles: &'static str,
        test: &'static str,
        tests: &'static str,
        bench: &'static str,
        benchs: &'static str,
        all: &'static str,
    ) -> Self {
        self.arg_targets_lib_bin(lib, bin, bins)
            ._arg(multi_opt("example", "NAME", examle))
            ._arg(opt("examples", examles))
            ._arg(multi_opt("test", "NAME", test))
            ._arg(opt("tests", tests))
            ._arg(multi_opt("bench", "NAME", bench))
            ._arg(opt("benches", benchs))
            ._arg(opt("all-targets", all))
    }

    fn arg_targets_lib_bin(self, lib: &'static str, bin: &'static str, bins: &'static str) -> Self {
        self._arg(opt("lib", lib))
            ._arg(multi_opt("bin", "NAME", bin))
            ._arg(opt("bins", bins))
    }

    fn arg_targets_bins_examples(
        self,
        bin: &'static str,
        bins: &'static str,
        example: &'static str,
        examples: &'static str,
    ) -> Self {
        self._arg(multi_opt("bin", "NAME", bin))
            ._arg(opt("bins", bins))
            ._arg(multi_opt("example", "NAME", example))
            ._arg(opt("examples", examples))
    }

    fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
        self._arg(multi_opt("bin", "NAME", bin))
            ._arg(multi_opt("example", "NAME", example))
    }

    fn arg_features(self) -> Self {
        self._arg(
            opt("features", "Space-separated list of features to activate").value_name("FEATURES"),
        )._arg(opt("all-features", "Activate all available features"))
            ._arg(opt(
                "no-default-features",
                "Do not activate the `default` feature",
            ))
    }

    fn arg_release(self, release: &'static str) -> Self {
        self._arg(opt("release", release))
    }

    fn arg_target_triple(self, target: &'static str) -> Self {
        self._arg(opt("target", target).value_name("TRIPLE"))
    }

    fn arg_manifest_path(self) -> Self {
        self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
    }

    fn arg_message_format(self) -> Self {
        self._arg(
            opt("message-format", "Error format")
                .value_name("FMT")
                .case_insensitive(true)
                .possible_values(&["human", "json"])
                .default_value("human"),
        )
    }

    fn arg_new_opts(self) -> Self {
        self._arg(
            opt(
                "vcs",
                "\
                 Initialize a new repository for the given version \
                 control system (git, hg, pijul, or fossil) or do not \
                 initialize any version control at all (none), overriding \
                 a global configuration.",
            ).value_name("VCS")
                .possible_values(&["git", "hg", "pijul", "fossil", "none"]),
        )._arg(opt("bin", "Use a binary (application) template [default]"))
            ._arg(opt("lib", "Use a library template"))
            ._arg(
                opt(
                    "name",
                    "Set the resulting package name, defaults to the directory name",
                ).value_name("NAME"),
            )
    }

    fn arg_index(self) -> Self {
        self._arg(opt("index", "Registry index to upload the package to").value_name("INDEX"))
            ._arg(
                opt("host", "DEPRECATED, renamed to '--index'")
                    .value_name("HOST")
                    .hidden(true),
            )
    }
}

impl AppExt for App {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self {
        self.arg(arg)
    }
}

pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
    Arg::with_name(name).long(name).help(help)
}

pub fn multi_opt(
    name: &'static str,
    value_name: &'static str,
    help: &'static str,
) -> Arg<'static, 'static> {
    // Note that all `.multiple(true)` arguments in Cargo should specify
    // `.number_of_values(1)` as well, so that `--foo val1 val2` is
    // **not** parsed as `foo` with values ["val1", "val2"].
    // `number_of_values` should become the default in clap 3.
    opt(name, help)
        .value_name(value_name)
        .multiple(true)
        .number_of_values(1)
}

pub fn subcommand(name: &'static str) -> App {
    SubCommand::with_name(name).settings(&[
        AppSettings::UnifiedHelpMessage,
        AppSettings::DeriveDisplayOrder,
        AppSettings::DontCollapseArgsInUsage,
    ])
}

pub trait ArgMatchesExt {
    fn value_of_u32(&self, name: &str) -> CargoResult<Option<u32>> {
        let arg = match self._value_of(name) {
            None => None,
            Some(arg) => Some(arg.parse::<u32>().map_err(|_| {
                clap::Error::value_validation_auto(format!("could not parse `{}` as a number", arg))
            })?),
        };
        Ok(arg)
    }

    /// Returns value of the `name` command-line argument as an absolute path
    fn value_of_path(&self, name: &str, config: &Config) -> Option<PathBuf> {
        self._value_of(name).map(|path| config.cwd().join(path))
    }

    fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
        if let Some(path) = self.value_of_path("manifest-path", config) {
            // In general, we try to avoid normalizing paths in Cargo,
            // but in this particular case we need it to fix #3586.
            let path = paths::normalize_path(&path);
            if !path.ends_with("Cargo.toml") {
                bail!("the manifest-path must be a path to a Cargo.toml file")
            }
            if !fs::metadata(&path).is_ok() {
                bail!(
                    "manifest path `{}` does not exist",
                    self._value_of("manifest-path").unwrap()
                )
            }
            return Ok(path);
        }
        find_root_manifest_for_wd(config.cwd())
    }

    fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>> {
        let root = self.root_manifest(config)?;
        let mut ws = Workspace::new(&root, config)?;
        if config.cli_unstable().avoid_dev_deps {
            ws.set_require_optional_deps(false);
        }
        Ok(ws)
    }

    fn jobs(&self) -> CargoResult<Option<u32>> {
        self.value_of_u32("jobs")
    }

    fn target(&self) -> Option<String> {
        self._value_of("target").map(|s| s.to_string())
    }

    fn compile_options<'a>(
        &self,
        config: &'a Config,
        mode: CompileMode,
    ) -> CargoResult<CompileOptions<'a>> {
        let spec = Packages::from_flags(
            self._is_present("all"),
            self._values_of("exclude"),
            self._values_of("package"),
        )?;

        let message_format = match self._value_of("message-format") {
            None => MessageFormat::Human,
            Some(f) => {
                if f.eq_ignore_ascii_case("json") {
                    MessageFormat::Json
                } else if f.eq_ignore_ascii_case("human") {
                    MessageFormat::Human
                } else {
                    panic!("Impossible message format: {:?}", f)
                }
            }
        };

        let opts = CompileOptions {
            config,
            jobs: self.jobs()?,
            target: self.target(),
            features: self._values_of("features"),
            all_features: self._is_present("all-features"),
            no_default_features: self._is_present("no-default-features"),
            spec,
            mode,
            release: self._is_present("release"),
            filter: CompileFilter::new(
                self._is_present("lib"),
                self._values_of("bin"),
                self._is_present("bins"),
                self._values_of("test"),
                self._is_present("tests"),
                self._values_of("example"),
                self._is_present("examples"),
                self._values_of("bench"),
                self._is_present("benches"),
                self._is_present("all-targets"),
            ),
            message_format,
            target_rustdoc_args: None,
            target_rustc_args: None,
            export_dir: None,
        };
        Ok(opts)
    }

    fn compile_options_for_single_package<'a>(
        &self,
        config: &'a Config,
        mode: CompileMode,
    ) -> CargoResult<CompileOptions<'a>> {
        let mut compile_opts = self.compile_options(config, mode)?;
        compile_opts.spec = Packages::Packages(self._values_of("package"));
        Ok(compile_opts)
    }

    fn new_options(&self, config: &Config) -> CargoResult<NewOptions> {
        let vcs = self._value_of("vcs").map(|vcs| match vcs {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "pijul" => VersionControl::Pijul,
            "fossil" => VersionControl::Fossil,
            "none" => VersionControl::NoVcs,
            vcs => panic!("Impossible vcs: {:?}", vcs),
        });
        NewOptions::new(
            vcs,
            self._is_present("bin"),
            self._is_present("lib"),
            self.value_of_path("path", config).unwrap(),
            self._value_of("name").map(|s| s.to_string()),
        )
    }

    fn registry(&self, config: &Config) -> CargoResult<Option<String>> {
        match self._value_of("registry") {
            Some(registry) => {
                if !config.cli_unstable().unstable_options {
                    return Err(format_err!(
                        "registry option is an unstable feature and \
                         requires -Zunstable-options to use."
                    ).into());
                }
                Ok(Some(registry.to_string()))
            }
            None => Ok(None),
        }
    }

    fn index(&self, config: &Config) -> CargoResult<Option<String>> {
        // TODO: Deprecated
        // remove once it has been decided --host can be removed
        // We may instead want to repurpose the host flag, as
        // mentioned in this issue
        // https://github.com/rust-lang/cargo/issues/4208
        let msg = "The flag '--host' is no longer valid.

Previous versions of Cargo accepted this flag, but it is being
deprecated. The flag is being renamed to 'index', as the flag
wants the location of the index. Please use '--index' instead.

This will soon become a hard error, so it's either recommended
to update to a fixed version or contact the upstream maintainer
about this warning.";

        let index = match self._value_of("host") {
            Some(host) => {
                config.shell().warn(&msg)?;
                Some(host.to_string())
            }
            None => self._value_of("index").map(|s| s.to_string()),
        };
        Ok(index)
    }

    fn _value_of(&self, name: &str) -> Option<&str>;

    fn _values_of(&self, name: &str) -> Vec<String>;

    fn _is_present(&self, name: &str) -> bool;
}

impl<'a> ArgMatchesExt for ArgMatches<'a> {
    fn _value_of(&self, name: &str) -> Option<&str> {
        self.value_of(name)
    }

    fn _values_of(&self, name: &str) -> Vec<String> {
        self.values_of(name)
            .unwrap_or_default()
            .map(|s| s.to_string())
            .collect()
    }

    fn _is_present(&self, name: &str) -> bool {
        self.is_present(name)
    }
}

pub fn values(args: &ArgMatches, name: &str) -> Vec<String> {
    args.values_of(name)
        .unwrap_or_default()
        .map(|s| s.to_string())
        .collect()
}
<commit_msg>Auto merge of #5396 - dwijnand:arg_targets_all-typos, r=matklad<commit_after>use std::path::PathBuf;
use std::fs;

use clap::{self, SubCommand};
use cargo::CargoResult;
use cargo::core::Workspace;
use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages,
                 VersionControl};
use cargo::util::paths;
use cargo::util::important_paths::find_root_manifest_for_wd;

pub use clap::{AppSettings, Arg, ArgMatches};
pub use cargo::{CliError, CliResult, Config};

pub type App = clap::App<'static, 'static>;

pub trait AppExt: Sized {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self;

    fn arg_package_spec(
        self,
        package: &'static str,
        all: &'static str,
        exclude: &'static str,
    ) -> Self {
        self.arg_package_spec_simple(package)
            ._arg(opt("all", all))
            ._arg(multi_opt("exclude", "SPEC", exclude))
    }

    fn arg_package_spec_simple(self, package: &'static str) -> Self {
        self._arg(multi_opt("package", "SPEC", package).short("p"))
    }

    fn arg_package(self, package: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC"))
    }

    fn arg_jobs(self) -> Self {
        self._arg(
            opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
                .short("j")
                .value_name("N"),
        )
    }

    fn arg_targets_all(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
        example: &'static str,
        examples: &'static str,
        test: &'static str,
        tests: &'static str,
        bench: &'static str,
        benches: &'static str,
        all: &'static str,
    ) -> Self {
        self.arg_targets_lib_bin(lib, bin, bins)
            ._arg(multi_opt("example", "NAME", example))
            ._arg(opt("examples", examples))
            ._arg(multi_opt("test", "NAME", test))
            ._arg(opt("tests", tests))
            ._arg(multi_opt("bench", "NAME", bench))
            ._arg(opt("benches", benches))
            ._arg(opt("all-targets", all))
    }

    fn arg_targets_lib_bin(self, lib: &'static str, bin: &'static str, bins: &'static str) -> Self {
        self._arg(opt("lib", lib))
            ._arg(multi_opt("bin", "NAME", bin))
            ._arg(opt("bins", bins))
    }

    fn arg_targets_bins_examples(
        self,
        bin: &'static str,
        bins: &'static str,
        example: &'static str,
        examples: &'static str,
    ) -> Self {
        self._arg(multi_opt("bin", "NAME", bin))
            ._arg(opt("bins", bins))
            ._arg(multi_opt("example", "NAME", example))
            ._arg(opt("examples", examples))
    }

    fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
        self._arg(multi_opt("bin", "NAME", bin))
            ._arg(multi_opt("example", "NAME", example))
    }

    fn arg_features(self) -> Self {
        self._arg(
            opt("features", "Space-separated list of features to activate").value_name("FEATURES"),
        )._arg(opt("all-features", "Activate all available features"))
            ._arg(opt(
                "no-default-features",
                "Do not activate the `default` feature",
            ))
    }

    fn arg_release(self, release: &'static str) -> Self {
        self._arg(opt("release", release))
    }

    fn arg_target_triple(self, target: &'static str) -> Self {
        self._arg(opt("target", target).value_name("TRIPLE"))
    }

    fn arg_manifest_path(self) -> Self {
        self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
    }

    fn arg_message_format(self) -> Self {
        self._arg(
            opt("message-format", "Error format")
                .value_name("FMT")
                .case_insensitive(true)
                .possible_values(&["human", "json"])
                .default_value("human"),
        )
    }

    fn arg_new_opts(self) -> Self {
        self._arg(
            opt(
                "vcs",
                "\
                 Initialize a new repository for the given version \
                 control system (git, hg, pijul, or fossil) or do not \
                 initialize any version control at all (none), overriding \
                 a global configuration.",
            ).value_name("VCS")
                .possible_values(&["git", "hg", "pijul", "fossil", "none"]),
        )._arg(opt("bin", "Use a binary (application) template [default]"))
            ._arg(opt("lib", "Use a library template"))
            ._arg(
                opt(
                    "name",
                    "Set the resulting package name, defaults to the directory name",
                ).value_name("NAME"),
            )
    }

    fn arg_index(self) -> Self {
        self._arg(opt("index", "Registry index to upload the package to").value_name("INDEX"))
            ._arg(
                opt("host", "DEPRECATED, renamed to '--index'")
                    .value_name("HOST")
                    .hidden(true),
            )
    }
}

impl AppExt for App {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self {
        self.arg(arg)
    }
}

pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
    Arg::with_name(name).long(name).help(help)
}

pub fn multi_opt(
    name: &'static str,
    value_name: &'static str,
    help: &'static str,
) -> Arg<'static, 'static> {
    // Note that all `.multiple(true)` arguments in Cargo should specify
    // `.number_of_values(1)` as well, so that `--foo val1 val2` is
    // **not** parsed as `foo` with values ["val1", "val2"].
    // `number_of_values` should become the default in clap 3.
    opt(name, help)
        .value_name(value_name)
        .multiple(true)
        .number_of_values(1)
}

pub fn subcommand(name: &'static str) -> App {
    SubCommand::with_name(name).settings(&[
        AppSettings::UnifiedHelpMessage,
        AppSettings::DeriveDisplayOrder,
        AppSettings::DontCollapseArgsInUsage,
    ])
}

pub trait ArgMatchesExt {
    fn value_of_u32(&self, name: &str) -> CargoResult<Option<u32>> {
        let arg = match self._value_of(name) {
            None => None,
            Some(arg) => Some(arg.parse::<u32>().map_err(|_| {
                clap::Error::value_validation_auto(format!("could not parse `{}` as a number", arg))
            })?),
        };
        Ok(arg)
    }

    /// Returns value of the `name` command-line argument as an absolute path
    fn value_of_path(&self, name: &str, config: &Config) -> Option<PathBuf> {
        self._value_of(name).map(|path| config.cwd().join(path))
    }

    fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
        if let Some(path) = self.value_of_path("manifest-path", config) {
            // In general, we try to avoid normalizing paths in Cargo,
            // but in this particular case we need it to fix #3586.
            let path = paths::normalize_path(&path);
            if !path.ends_with("Cargo.toml") {
                bail!("the manifest-path must be a path to a Cargo.toml file")
            }
            if !fs::metadata(&path).is_ok() {
                bail!(
                    "manifest path `{}` does not exist",
                    self._value_of("manifest-path").unwrap()
                )
            }
            return Ok(path);
        }
        find_root_manifest_for_wd(config.cwd())
    }

    fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>> {
        let root = self.root_manifest(config)?;
        let mut ws = Workspace::new(&root, config)?;
        if config.cli_unstable().avoid_dev_deps {
            ws.set_require_optional_deps(false);
        }
        Ok(ws)
    }

    fn jobs(&self) -> CargoResult<Option<u32>> {
        self.value_of_u32("jobs")
    }

    fn target(&self) -> Option<String> {
        self._value_of("target").map(|s| s.to_string())
    }

    fn compile_options<'a>(
        &self,
        config: &'a Config,
        mode: CompileMode,
    ) -> CargoResult<CompileOptions<'a>> {
        let spec = Packages::from_flags(
            self._is_present("all"),
            self._values_of("exclude"),
            self._values_of("package"),
        )?;

        let message_format = match self._value_of("message-format") {
            None => MessageFormat::Human,
            Some(f) => {
                if f.eq_ignore_ascii_case("json") {
                    MessageFormat::Json
                } else if f.eq_ignore_ascii_case("human") {
                    MessageFormat::Human
                } else {
                    panic!("Impossible message format: {:?}", f)
                }
            }
        };

        let opts = CompileOptions {
            config,
            jobs: self.jobs()?,
            target: self.target(),
            features: self._values_of("features"),
            all_features: self._is_present("all-features"),
            no_default_features: self._is_present("no-default-features"),
            spec,
            mode,
            release: self._is_present("release"),
            filter: CompileFilter::new(
                self._is_present("lib"),
                self._values_of("bin"),
                self._is_present("bins"),
                self._values_of("test"),
                self._is_present("tests"),
                self._values_of("example"),
                self._is_present("examples"),
                self._values_of("bench"),
                self._is_present("benches"),
                self._is_present("all-targets"),
            ),
            message_format,
            target_rustdoc_args: None,
            target_rustc_args: None,
            export_dir: None,
        };
        Ok(opts)
    }

    fn compile_options_for_single_package<'a>(
        &self,
        config: &'a Config,
        mode: CompileMode,
    ) -> CargoResult<CompileOptions<'a>> {
        let mut compile_opts = self.compile_options(config, mode)?;
        compile_opts.spec = Packages::Packages(self._values_of("package"));
        Ok(compile_opts)
    }

    fn new_options(&self, config: &Config) -> CargoResult<NewOptions> {
        let vcs = self._value_of("vcs").map(|vcs| match vcs {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "pijul" => VersionControl::Pijul,
            "fossil" => VersionControl::Fossil,
            "none" => VersionControl::NoVcs,
            vcs => panic!("Impossible vcs: {:?}", vcs),
        });
        NewOptions::new(
            vcs,
            self._is_present("bin"),
            self._is_present("lib"),
            self.value_of_path("path", config).unwrap(),
            self._value_of("name").map(|s| s.to_string()),
        )
    }

    fn registry(&self, config: &Config) -> CargoResult<Option<String>> {
        match self._value_of("registry") {
            Some(registry) => {
                if !config.cli_unstable().unstable_options {
                    return Err(format_err!(
                        "registry option is an unstable feature and \
                         requires -Zunstable-options to use."
                    ).into());
                }
                Ok(Some(registry.to_string()))
            }
            None => Ok(None),
        }
    }

    fn index(&self, config: &Config) -> CargoResult<Option<String>> {
        // TODO: Deprecated
        // remove once it has been decided --host can be removed
        // We may instead want to repurpose the host flag, as
        // mentioned in this issue
        // https://github.com/rust-lang/cargo/issues/4208
        let msg = "The flag '--host' is no longer valid.

Previous versions of Cargo accepted this flag, but it is being
deprecated. The flag is being renamed to 'index', as the flag
wants the location of the index. Please use '--index' instead.

This will soon become a hard error, so it's either recommended
to update to a fixed version or contact the upstream maintainer
about this warning.";

        let index = match self._value_of("host") {
            Some(host) => {
                config.shell().warn(&msg)?;
                Some(host.to_string())
            }
            None => self._value_of("index").map(|s| s.to_string()),
        };
        Ok(index)
    }

    fn _value_of(&self, name: &str) -> Option<&str>;

    fn _values_of(&self, name: &str) -> Vec<String>;

    fn _is_present(&self, name: &str) -> bool;
}

impl<'a> ArgMatchesExt for ArgMatches<'a> {
    fn _value_of(&self, name: &str) -> Option<&str> {
        self.value_of(name)
    }

    fn _values_of(&self, name: &str) -> Vec<String> {
        self.values_of(name)
            .unwrap_or_default()
            .map(|s| s.to_string())
            .collect()
    }

    fn _is_present(&self, name: &str) -> bool {
        self.is_present(name)
    }
}

pub fn values(args: &ArgMatches, name: &str) -> Vec<String> {
    args.values_of(name)
        .unwrap_or_default()
        .map(|s| s.to_string())
        .collect()
}
<|endoftext|>


<commit_before>// TODO: remove below
#![allow(dead_code)]

//let leftBlockDelim: String = "{%".to_string();
//let rightBlockDelim: String = "%}".to_string();
const LEFT_VARIABLE_DELIM: &'static str  = "{{";
const RIGHT_VARIABLE_DELIM: &'static str  = "}}";

// List of token types to emit to the parser.
// Different from the state enum despite some identical members
#[derive(PartialEq, Debug)]
pub enum TokenType {
  Text, // HTML text etc
  Space,
  VariableStart, // {{
  VariableEnd, // }}
  Variable, // variable name, tera keywords
  Int,
  Float,
  Operator, // + - * / .
  Error, // errors uncountered while lexing, such as 1.2.3 number
}

// List of different states the Tokenizer can be in
#[derive(Debug)]
enum State {
  Text,
  VariableStart,
  InsideBlock,
}

#[derive(PartialEq, Debug)]
pub struct Token {
  kind: TokenType,
  value: String,
}

impl Token {
  pub fn new(kind: TokenType, value: &str) -> Token {
    Token {
      kind: kind,
      value: value.to_string()
    }
  }
}

#[derive(Debug)]
pub struct Tokenizer {
  name: String,
  input: String,
  chars: Vec<(usize, char)>, // (bytes index, char)
  index: usize, // where we are in the chars vec
  state: State,
}

impl Tokenizer {
  pub fn new(input: &str) -> Tokenizer {
    // We want to figure out what's the initial state so we check the first
    // 2 chars
    let first_chars = input.chars().take(2).collect::<String>();
    // TODO: &* is pretty ugly, any way to fix that?
    let state = match &*first_chars {
      "{{" => State::VariableStart,
      _ => State::Text
    };

    Tokenizer {
      name: "test".to_string(),
      input: input.to_string(),
      chars: input.char_indices().collect(),
      index: 0,
      state: state,
    }
  }

  // Gets the substring a start index and self.index
  // Substring is non-inclusive
  fn get_substring(&self, start: usize) -> &str {
    let start_bytes = self.chars[start].0;
    let end_bytes = self.chars[self.index].0;

    // special case if the end index is the last char
    if self.is_over() {
      return &self.input[start_bytes..];
    }

    &self.input[start_bytes..end_bytes]
  }

  // We'll want to make sure we don't continue after the end in several
  // lexer methods
  fn is_over(&self) -> bool {
    self.index >= self.chars.len() - 1
  }

  // We know we have {{ with self.index being on the first
  fn lex_left_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::InsideBlock;

    Token::new(TokenType::VariableStart, "{{")
  }

  // TODO: merge with the one above?
  fn lex_right_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::Text;

    Token::new(TokenType::VariableEnd, "}}")
  }

  fn lex_text(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if self.input[self.chars[self.index].0..].starts_with(LEFT_VARIABLE_DELIM) {
        self.state = State::VariableStart;
        break;
      }

      if self.is_over() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Text, self.get_substring(start_index))
  }

  // We know we have a space, we need to figure out how many
  fn lex_space(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if !self.chars[self.index].1.is_whitespace() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Space, self.get_substring(start_index))
  }

  fn lex_number(&mut self) -> Token {
    let start_index = self.index;
    let mut number_type = TokenType::Int;
    let mut error = "";

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '}' => break,
        '.' => {
          match number_type {
            TokenType::Int => number_type = TokenType::Float,
            TokenType::Float => error = "A number has 2 dots",
            _ => {}
          }
        },
        x if !x.is_numeric() => error = "A number has unallowed chars",
        _ => {}
      }
      self.index += 1;
    }

    if error.len() > 0 {
      return Token::new(TokenType::Error, error);
    }

    Token::new(number_type, self.get_substring(start_index))
  }

  fn lex_variable(&mut self) -> Token {
    let start_index = self.index;

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '.' => break,
        _ => {}
      }
      self.index += 1;
    }

    Token::new(TokenType::Variable, self.get_substring(start_index))
  }

  fn lex_operator(&mut self) -> Token {
    self.index += 1;
    self.state = State::InsideBlock;

    Token::new(TokenType::Operator, self.get_substring(self.index - 1))
  }

  fn lex_inside_variable_block(&mut self) -> Token {
    match self.chars[self.index].1 {
      x if x.is_whitespace() => self.lex_space(),
      x if x.is_alphabetic() || x == '_' => self.lex_variable(),
      '}' => self.lex_right_variable_delimiter(),
      x if x.is_numeric() => self.lex_number(),
      '*' | '+' | '-' | '/' | '.' => self.lex_operator(),
      _ => Token::new(TokenType::Error, "Unknown char in variable block"),
    }
  }
}

impl Iterator for Tokenizer {
  type Item = Token;

  fn next(&mut self) -> Option<Token> {
    // Empty template
    if self.input.len() == 0 {
      return None;
    }

    // Got to the end
    if self.is_over() {
      return None;
    }

    match self.state {
      State::Text => Some(self.lex_text()),
      State::VariableStart => Some(self.lex_left_variable_delimiter()),
      State::InsideBlock => Some(self.lex_inside_variable_block()),
      _ => None,
    }
  }
}

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

  #[derive(Debug)]
  struct LexerTest {
    name: String,
    input: String,
    expected: Vec<Token>
  }

  impl LexerTest {
    pub fn new(name: &str, input: &str, expected: Vec<Token>) -> LexerTest {
      LexerTest {
        name: name.to_string(),
        input: input.to_string(),
        expected: expected
      }
    }
  }

  fn text_token(value: &str) -> Token {
    Token::new(TokenType::Text, value)
  }

  fn variable_token(value: &str) -> Token {
    Token::new(TokenType::Variable, value)
  }

  fn variable_start_token() -> Token {
    Token::new(TokenType::VariableStart, "{{")
  }

  fn variable_end_token() -> Token {
    Token::new(TokenType::VariableEnd, "}}")
  }

  fn space_token() -> Token {
    Token::new(TokenType::Space, " ")
  }

  fn int_token(value: &str) -> Token {
    Token::new(TokenType::Int, value)
  }

  fn float_token(value: &str) -> Token {
    Token::new(TokenType::Float, value)
  }

  fn operator_token(value: &str) -> Token {
    Token::new(TokenType::Operator, value)
  }

  fn error_token() -> Token {
    Token::new(TokenType::Error, "")
  }

  fn check_if_correct(expected: &Vec<Token>, obtained: &Vec<Token>) -> bool {
    if expected.len() != obtained.len() {
      return false;
    }

    for i in 0..expected.len() {
      if expected[i].kind != obtained[i].kind {
        return false;
      }

      // Do not check error values as i'll probably change them often
      if expected[i].kind == TokenType::Error {
        continue;
      }

      if expected[i].value != obtained[i].value {
        return false;
      }
    }
    return true;
  }

  #[test]
  fn test_lexer() {
    let tests: Vec<LexerTest> = vec![
      LexerTest::new("empty", "", vec![]),
      LexerTest::new("only text", "Hello 世界", vec![text_token("Hello 世界")]),
      LexerTest::new("variable and text", "{{ greeting }} 世界", vec![
        variable_start_token(),
        space_token(),
        variable_token("greeting"),
        space_token(),
        variable_end_token(),
        text_token(" 世界"),
      ]),
      LexerTest::new("numbers", "{{1 3.14}}", vec![
        variable_start_token(),
        int_token("1"),
        space_token(),
        float_token("3.14"),
        variable_end_token(),
      ]),
      LexerTest::new("invalid numbers", "{{1up 3.14.15}}", vec![
        variable_start_token(),
        error_token(),
        space_token(),
        error_token(),
        variable_end_token(),
      ]),
      LexerTest::new("operators", "{{+ - * / .}}", vec![
        variable_start_token(),
        operator_token("+"),
        space_token(),
        operator_token("-"),
        space_token(),
        operator_token("*"),
        space_token(),
        operator_token("/"),
        space_token(),
        operator_token("."),
        variable_end_token(),
      ])
    ];

    for test in tests {
      let tokens: Vec<Token> = Tokenizer::new(&test.input).collect();
      if tokens.len() != test.expected.len() {
        println!("Test {} failed: different number of tokens.", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }

      if check_if_correct(&test.expected, &tokens) {
        assert!(true);
      } else {
        println!("Test {} failed: different tokens", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }
    }
  }
}
<commit_msg>Some more cleanup<commit_after>const LEFT_VARIABLE_DELIM: &'static str  = "{{";
//const RIGHT_VARIABLE_DELIM: &'static str  = "}}";

// List of token types to emit to the parser.
// Different from the state enum despite some identical members
#[derive(PartialEq, Debug)]
pub enum TokenType {
  Text, // HTML text etc
  Space,
  VariableStart, // {{
  VariableEnd, // }}
  Variable, // variable name, tera keywords
  Int,
  Float,
  Operator, // + - * / .
  Error, // errors uncountered while lexing, such as 1.2.3 number
}

// List of different states the Tokenizer can be in
#[derive(Debug)]
enum State {
  Text,
  VariableStart,
  InsideBlock,
}

#[derive(PartialEq, Debug)]
pub struct Token {
  kind: TokenType,
  value: String,
}

impl Token {
  pub fn new(kind: TokenType, value: &str) -> Token {
    Token {
      kind: kind,
      value: value.to_string()
    }
  }
}

#[derive(Debug)]
pub struct Tokenizer {
  name: String,
  input: String,
  chars: Vec<(usize, char)>, // (bytes index, char)
  index: usize, // where we are in the chars vec
  state: State,
}

impl Tokenizer {
  pub fn new(input: &str) -> Tokenizer {
    // We want to figure out what's the initial state so we check the first
    // 2 chars
    let first_chars = input.chars().take(2).collect::<String>();
    // TODO: &* is pretty ugly, any way to fix that?
    let state = match &*first_chars {
      "{{" => State::VariableStart,
      _ => State::Text
    };

    Tokenizer {
      name: "test".to_string(),
      input: input.to_string(),
      chars: input.char_indices().collect(),
      index: 0,
      state: state,
    }
  }

  // Gets the substring a start index and self.index
  // Substring is non-inclusive
  fn get_substring(&self, start: usize) -> &str {
    let start_bytes = self.chars[start].0;
    let end_bytes = self.chars[self.index].0;

    // special case if the end index is the last char
    if self.is_over() {
      return &self.input[start_bytes..];
    }

    &self.input[start_bytes..end_bytes]
  }

  // We'll want to make sure we don't continue after the end in several
  // lexer methods
  fn is_over(&self) -> bool {
    self.index >= self.chars.len() - 1
  }

  // We know we have {{ with self.index being on the first
  fn lex_left_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::InsideBlock;

    Token::new(TokenType::VariableStart, "{{")
  }

  // TODO: merge with the one above?
  fn lex_right_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::Text;

    Token::new(TokenType::VariableEnd, "}}")
  }

  fn lex_text(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if self.input[self.chars[self.index].0..].starts_with(LEFT_VARIABLE_DELIM) {
        self.state = State::VariableStart;
        break;
      }

      if self.is_over() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Text, self.get_substring(start_index))
  }

  // We know we have a space, we need to figure out how many
  fn lex_space(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if !self.chars[self.index].1.is_whitespace() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Space, self.get_substring(start_index))
  }

  fn lex_number(&mut self) -> Token {
    let start_index = self.index;
    let mut number_type = TokenType::Int;
    let mut error = "";

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '}' => break,
        '.' => {
          match number_type {
            TokenType::Int => number_type = TokenType::Float,
            TokenType::Float => error = "A number has 2 dots",
            _ => {}
          }
        },
        x if !x.is_numeric() => error = "A number has unallowed chars",
        _ => {}
      }
      self.index += 1;
    }

    if error.len() > 0 {
      return Token::new(TokenType::Error, error);
    }

    Token::new(number_type, self.get_substring(start_index))
  }

  fn lex_variable(&mut self) -> Token {
    let start_index = self.index;

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '.' => break,
        _ => {}
      }
      self.index += 1;
    }

    Token::new(TokenType::Variable, self.get_substring(start_index))
  }

  fn lex_operator(&mut self) -> Token {
    self.index += 1;
    self.state = State::InsideBlock;

    Token::new(TokenType::Operator, self.get_substring(self.index - 1))
  }

  fn lex_inside_variable_block(&mut self) -> Token {
    match self.chars[self.index].1 {
      x if x.is_whitespace() => self.lex_space(),
      x if x.is_alphabetic() || x == '_' => self.lex_variable(),
      '}' => self.lex_right_variable_delimiter(),
      x if x.is_numeric() => self.lex_number(),
      '*' | '+' | '-' | '/' | '.' => self.lex_operator(),
      _ => Token::new(TokenType::Error, "Unknown char in variable block"),
    }
  }
}

impl Iterator for Tokenizer {
  type Item = Token;

  fn next(&mut self) -> Option<Token> {
    // Empty template or we got to the end
    if self.input.len() == 0 || self.is_over() {
      return None;
    }

    match self.state {
      State::Text => Some(self.lex_text()),
      State::VariableStart => Some(self.lex_left_variable_delimiter()),
      State::InsideBlock => Some(self.lex_inside_variable_block()),
    }
  }
}

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

  #[derive(Debug)]
  struct LexerTest {
    name: String,
    input: String,
    expected: Vec<Token>
  }

  impl LexerTest {
    pub fn new(name: &str, input: &str, expected: Vec<Token>) -> LexerTest {
      LexerTest {
        name: name.to_string(),
        input: input.to_string(),
        expected: expected
      }
    }
  }

  fn text_token(value: &str) -> Token {
    Token::new(TokenType::Text, value)
  }

  fn variable_token(value: &str) -> Token {
    Token::new(TokenType::Variable, value)
  }

  fn variable_start_token() -> Token {
    Token::new(TokenType::VariableStart, "{{")
  }

  fn variable_end_token() -> Token {
    Token::new(TokenType::VariableEnd, "}}")
  }

  fn space_token() -> Token {
    Token::new(TokenType::Space, " ")
  }

  fn int_token(value: &str) -> Token {
    Token::new(TokenType::Int, value)
  }

  fn float_token(value: &str) -> Token {
    Token::new(TokenType::Float, value)
  }

  fn operator_token(value: &str) -> Token {
    Token::new(TokenType::Operator, value)
  }

  fn error_token() -> Token {
    Token::new(TokenType::Error, "")
  }

  fn check_if_correct(expected: &Vec<Token>, obtained: &Vec<Token>) -> bool {
    if expected.len() != obtained.len() {
      return false;
    }

    for i in 0..expected.len() {
      if expected[i].kind != obtained[i].kind {
        return false;
      }

      // Do not check error values as i'll probably change them often
      if expected[i].kind == TokenType::Error {
        continue;
      }

      if expected[i].value != obtained[i].value {
        return false;
      }
    }
    return true;
  }

  #[test]
  fn test_lexer() {
    let tests: Vec<LexerTest> = vec![
      LexerTest::new("empty", "", vec![]),
      LexerTest::new("only text", "Hello 世界", vec![text_token("Hello 世界")]),
      LexerTest::new("variable and text", "{{ greeting }} 世界", vec![
        variable_start_token(),
        space_token(),
        variable_token("greeting"),
        space_token(),
        variable_end_token(),
        text_token(" 世界"),
      ]),
      LexerTest::new("numbers", "{{1 3.14}}", vec![
        variable_start_token(),
        int_token("1"),
        space_token(),
        float_token("3.14"),
        variable_end_token(),
      ]),
      LexerTest::new("invalid numbers", "{{1up 3.14.15}}", vec![
        variable_start_token(),
        error_token(),
        space_token(),
        error_token(),
        variable_end_token(),
      ]),
      LexerTest::new("operators", "{{+ - * / .}}", vec![
        variable_start_token(),
        operator_token("+"),
        space_token(),
        operator_token("-"),
        space_token(),
        operator_token("*"),
        space_token(),
        operator_token("/"),
        space_token(),
        operator_token("."),
        variable_end_token(),
      ])
    ];

    for test in tests {
      let tokens: Vec<Token> = Tokenizer::new(&test.input).collect();
      if tokens.len() != test.expected.len() {
        println!("Test {} failed: different number of tokens.", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }

      if check_if_correct(&test.expected, &tokens) {
        assert!(true);
      } else {
        println!("Test {} failed: different tokens", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use clap::{self, SubCommand, AppSettings, ArgMatches};
use cargo::{Config, CargoResult};
use cargo::core::Workspace;
use cargo::ops::{CompileMode, CompileOptions, CompileFilter, Packages, MessageFormat,
                 VersionControl, NewOptions};
use cargo::util::important_paths::find_root_manifest_for_wd;

pub use clap::Arg;

pub type App = clap::App<'static, 'static>;

pub trait CommonArgs: Sized {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self;

    fn arg_package(self, package: &'static str, all: &'static str, exclude: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC").multiple(true))
            ._arg(opt("all", all))
            ._arg(opt("exclude", exclude).value_name("SPEC").multiple(true))
    }

    fn arg_single_package(self, package: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC"))
    }

    fn arg_jobs(self) -> Self {
        self._arg(
            opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
                .short("j").value_name("N")
        )
    }

    fn arg_targets_all(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
        examle: &'static str,
        examles: &'static str,
        test: &'static str,
        tests: &'static str,
        bench: &'static str,
        benchs: &'static str,
        all: &'static str,
    ) -> Self {
        self.arg_targets_lib_bin(lib, bin, bins)
            ._arg(opt("example", examle).value_name("NAME").multiple(true))
            ._arg(opt("examples", examles))
            ._arg(opt("test", test).value_name("NAME").multiple(true))
            ._arg(opt("tests", tests))
            ._arg(opt("bench", bench).value_name("NAME").multiple(true))
            ._arg(opt("benches", benchs))
            ._arg(opt("all-targets", all))
    }

    fn arg_targets_lib_bin(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
    ) -> Self {
        self._arg(opt("lib", lib))
            ._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("bins", bins))
    }

    fn arg_targets_bins_examples(
        self,
        bin: &'static str,
        bins: &'static str,
        example: &'static str,
        examples: &'static str,
    ) -> Self {
        self._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("bins", bins))
            ._arg(opt("example", example).value_name("NAME").multiple(true))
            ._arg(opt("examples", examples))
    }

    fn arg_targets_bin_example(
        self,
        bin: &'static str,
        example: &'static str,
    ) -> Self {
        self._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("example", example).value_name("NAME").multiple(true))
    }

    fn arg_features(self) -> Self {
        self
            ._arg(
                opt("features", "Space-separated list of features to activate")
                    .value_name("FEATURES")
            )
            ._arg(opt("all-features", "Activate all available features"))
            ._arg(opt("no-default-features", "Do not activate the `default` feature"))
    }

    fn arg_release(self, release: &'static str) -> Self {
        self._arg(opt("release", release))
    }

    fn arg_target_triple(self, target: &'static str) -> Self {
        self._arg(opt("target", target).value_name("TRIPLE"))
    }

    fn arg_manifest_path(self) -> Self {
        self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
    }

    fn arg_message_format(self) -> Self {
        self._arg(
            opt("message-format", "Error format")
                .value_name("FMT")
                .case_insensitive(true)
                .possible_values(&["human", "json"]).default_value("human")
        )
    }

    fn arg_new_opts(self) -> Self {
        self._arg(
            opt("vcs", "\
Initialize a new repository for the given version \
control system (git, hg, pijul, or fossil) or do not \
initialize any version control at all (none), overriding \
a global configuration.")
                .value_name("VCS")
                .possible_values(&["git", "hg", "pijul", "fossil", "none"])
        )
            ._arg(opt("bin", "Use a binary (application) template [default]"))
            ._arg(opt("lib", "Use a library template"))
            ._arg(
                opt("name", "Set the resulting package name, defaults to the directory name")
                    .value_name("NAME")
            )
    }

    fn arg_index(self) -> Self {
        self
            ._arg(
                opt("index", "Registry index to upload the package to")
                    .value_name("INDEX")
            )
            ._arg(
                opt("host", "DEPRECATED, renamed to '--index'")
                    .value_name("HOST")
                    .hidden(true)
            )
    }
}

impl CommonArgs for App {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self {
        self.arg(arg)
    }
}

pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
    Arg::with_name(name).long(name).help(help)
}

pub fn subcommand(name: &'static str) -> App {
    SubCommand::with_name(name)
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::DontCollapseArgsInUsage,
        ])
}

pub fn values(args: &ArgMatches, name: &str) -> Vec<String> {
    args.values_of(name).unwrap_or_default()
        .map(|s| s.to_string())
        .collect()
}

pub fn config_from_args(config: &mut Config, args: &ArgMatches) -> CargoResult<()> {
    let color = args.value_of("color").map(|s| s.to_string());
    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quite") { Some(true) } else { None },
        &color,
        args.is_present("frozen"),
        args.is_present("locked"),
        &args.values_of_lossy("unstable-features").unwrap_or_default(),
    )
}

pub fn root_manifest_from_args(config: &Config, args: &ArgMatches) -> CargoResult<PathBuf> {
    let manifest_path = args.value_of("manifest-path").map(|s| s.to_string());
    find_root_manifest_for_wd(manifest_path, config.cwd())
}

pub fn workspace_from_args<'a>(config: &'a Config, args: &ArgMatches) -> CargoResult<Workspace<'a>> {
    let root = root_manifest_from_args(config, args)?;
    Workspace::new(&root, config)
}

pub fn jobs_from_args(args: &ArgMatches) -> CargoResult<Option<u32>> { //FIXME: validation
    let jobs = match args.value_of("jobs") {
        None => None,
        Some(jobs) => Some(jobs.parse::<u32>().map_err(|_| {
            clap::Error::value_validation_auto(
                format!("could not parse `{}` as a number", jobs)
            )
        })?)
    };
    Ok(jobs)
}

pub fn compile_options_from_args<'a>(
    config: &'a Config,
    args: &'a ArgMatches<'a>,
    mode: CompileMode,
) -> CargoResult<CompileOptions<'a>> {
    let spec = Packages::from_flags(
        args.is_present("all"),
        values(args, "exclude"),
        values(args, "package"),
    )?;

    let message_format = match args.value_of("message-format") {
        None => MessageFormat::Human,
        Some(f) => {
            if f.eq_ignore_ascii_case("json") {
                MessageFormat::Json
            } else if f.eq_ignore_ascii_case("human") {
                MessageFormat::Human
            } else {
                panic!("Impossible message format: {:?}", f)
            }
        }
    };

    let opts = CompileOptions {
        config,
        jobs: jobs_from_args(args)?,
        target: args.value_of("target"),
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        spec,
        mode,
        release: args.is_present("release"),
        filter: CompileFilter::new(args.is_present("lib"),
                                   values(args, "bin"), args.is_present("bins"),
                                   values(args, "test"), args.is_present("tests"),
                                   values(args, "example"), args.is_present("examples"),
                                   values(args, "bench"), args.is_present("benches"),
                                   args.is_present("all-targets")),
        message_format,
        target_rustdoc_args: None,
        target_rustc_args: None,
    };
    Ok(opts)
}

pub fn compile_options_from_args_for_single_package<'a>(
    config: &'a Config,
    args: &'a ArgMatches<'a>,
    mode: CompileMode,
) -> CargoResult<CompileOptions<'a>> {
    let mut compile_opts = compile_options_from_args(config, args, mode)?;
    compile_opts.spec = Packages::Packages(values(args, "package"));
    Ok(compile_opts)
}

pub fn new_opts_from_args<'a>(args: &'a ArgMatches<'a>, path: &'a str) -> CargoResult<NewOptions<'a>> {
    let vcs = args.value_of("vcs").map(|vcs| match vcs {
        "git" => VersionControl::Git,
        "hg" => VersionControl::Hg,
        "pijul" => VersionControl::Pijul,
        "fossil" => VersionControl::Fossil,
        "none" => VersionControl::NoVcs,
        vcs => panic!("Impossible vcs: {:?}", vcs),
    });
    NewOptions::new(vcs,
                    args.is_present("bin"),
                    args.is_present("lib"),
                    path,
                    args.value_of("name"))
}

pub fn registry_from_args(config: &Config, args: &ArgMatches) -> CargoResult<Option<String>> {
    match args.value_of("registry") {
        Some(registry) => {
            if !config.cli_unstable().unstable_options {
                return Err(format_err!("registry option is an unstable feature and \
                            requires -Zunstable-options to use.").into());
            }
            Ok(Some(registry.to_string()))
        }
        None => Ok(None),
    }
}

pub fn index_from_args(config: &Config, args: &ArgMatches) -> CargoResult<Option<String>> {
    // TODO: Deprecated
    // remove once it has been decided --host can be removed
    // We may instead want to repurpose the host flag, as
    // mentioned in this issue
    // https://github.com/rust-lang/cargo/issues/4208
    let msg = "The flag '--host' is no longer valid.

Previous versions of Cargo accepted this flag, but it is being
deprecated. The flag is being renamed to 'index', as the flag
wants the location of the index. Please use '--index' instead.

This will soon become a hard error, so it's either recommended
to update to a fixed version or contact the upstream maintainer
about this warning.";

    let index = match args.value_of("host") {
        Some(host) => {
            config.shell().warn(&msg)?;
            Some(host.to_string())
        }
        None => args.value_of("index").map(|s| s.to_string())
    };
    Ok(index)
}
<commit_msg>Rename CommonArgs -> AppExt<commit_after>use std::path::PathBuf;

use clap::{self, SubCommand, AppSettings, ArgMatches};
use cargo::{Config, CargoResult};
use cargo::core::Workspace;
use cargo::ops::{CompileMode, CompileOptions, CompileFilter, Packages, MessageFormat,
                 VersionControl, NewOptions};
use cargo::util::important_paths::find_root_manifest_for_wd;

pub use clap::Arg;

pub type App = clap::App<'static, 'static>;

pub trait AppExt: Sized {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self;

    fn arg_package(self, package: &'static str, all: &'static str, exclude: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC").multiple(true))
            ._arg(opt("all", all))
            ._arg(opt("exclude", exclude).value_name("SPEC").multiple(true))
    }

    fn arg_single_package(self, package: &'static str) -> Self {
        self._arg(opt("package", package).short("p").value_name("SPEC"))
    }

    fn arg_jobs(self) -> Self {
        self._arg(
            opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
                .short("j").value_name("N")
        )
    }

    fn arg_targets_all(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
        examle: &'static str,
        examles: &'static str,
        test: &'static str,
        tests: &'static str,
        bench: &'static str,
        benchs: &'static str,
        all: &'static str,
    ) -> Self {
        self.arg_targets_lib_bin(lib, bin, bins)
            ._arg(opt("example", examle).value_name("NAME").multiple(true))
            ._arg(opt("examples", examles))
            ._arg(opt("test", test).value_name("NAME").multiple(true))
            ._arg(opt("tests", tests))
            ._arg(opt("bench", bench).value_name("NAME").multiple(true))
            ._arg(opt("benches", benchs))
            ._arg(opt("all-targets", all))
    }

    fn arg_targets_lib_bin(
        self,
        lib: &'static str,
        bin: &'static str,
        bins: &'static str,
    ) -> Self {
        self._arg(opt("lib", lib))
            ._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("bins", bins))
    }

    fn arg_targets_bins_examples(
        self,
        bin: &'static str,
        bins: &'static str,
        example: &'static str,
        examples: &'static str,
    ) -> Self {
        self._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("bins", bins))
            ._arg(opt("example", example).value_name("NAME").multiple(true))
            ._arg(opt("examples", examples))
    }

    fn arg_targets_bin_example(
        self,
        bin: &'static str,
        example: &'static str,
    ) -> Self {
        self._arg(opt("bin", bin).value_name("NAME").multiple(true))
            ._arg(opt("example", example).value_name("NAME").multiple(true))
    }

    fn arg_features(self) -> Self {
        self
            ._arg(
                opt("features", "Space-separated list of features to activate")
                    .value_name("FEATURES")
            )
            ._arg(opt("all-features", "Activate all available features"))
            ._arg(opt("no-default-features", "Do not activate the `default` feature"))
    }

    fn arg_release(self, release: &'static str) -> Self {
        self._arg(opt("release", release))
    }

    fn arg_target_triple(self, target: &'static str) -> Self {
        self._arg(opt("target", target).value_name("TRIPLE"))
    }

    fn arg_manifest_path(self) -> Self {
        self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
    }

    fn arg_message_format(self) -> Self {
        self._arg(
            opt("message-format", "Error format")
                .value_name("FMT")
                .case_insensitive(true)
                .possible_values(&["human", "json"]).default_value("human")
        )
    }

    fn arg_new_opts(self) -> Self {
        self._arg(
            opt("vcs", "\
Initialize a new repository for the given version \
control system (git, hg, pijul, or fossil) or do not \
initialize any version control at all (none), overriding \
a global configuration.")
                .value_name("VCS")
                .possible_values(&["git", "hg", "pijul", "fossil", "none"])
        )
            ._arg(opt("bin", "Use a binary (application) template [default]"))
            ._arg(opt("lib", "Use a library template"))
            ._arg(
                opt("name", "Set the resulting package name, defaults to the directory name")
                    .value_name("NAME")
            )
    }

    fn arg_index(self) -> Self {
        self
            ._arg(
                opt("index", "Registry index to upload the package to")
                    .value_name("INDEX")
            )
            ._arg(
                opt("host", "DEPRECATED, renamed to '--index'")
                    .value_name("HOST")
                    .hidden(true)
            )
    }
}

impl AppExt for App {
    fn _arg(self, arg: Arg<'static, 'static>) -> Self {
        self.arg(arg)
    }
}

pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
    Arg::with_name(name).long(name).help(help)
}

pub fn subcommand(name: &'static str) -> App {
    SubCommand::with_name(name)
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::DontCollapseArgsInUsage,
        ])
}

pub fn values(args: &ArgMatches, name: &str) -> Vec<String> {
    args.values_of(name).unwrap_or_default()
        .map(|s| s.to_string())
        .collect()
}

pub fn config_from_args(config: &mut Config, args: &ArgMatches) -> CargoResult<()> {
    let color = args.value_of("color").map(|s| s.to_string());
    config.configure(
        args.occurrences_of("verbose") as u32,
        if args.is_present("quite") { Some(true) } else { None },
        &color,
        args.is_present("frozen"),
        args.is_present("locked"),
        &args.values_of_lossy("unstable-features").unwrap_or_default(),
    )
}

pub fn root_manifest_from_args(config: &Config, args: &ArgMatches) -> CargoResult<PathBuf> {
    let manifest_path = args.value_of("manifest-path").map(|s| s.to_string());
    find_root_manifest_for_wd(manifest_path, config.cwd())
}

pub fn workspace_from_args<'a>(config: &'a Config, args: &ArgMatches) -> CargoResult<Workspace<'a>> {
    let root = root_manifest_from_args(config, args)?;
    Workspace::new(&root, config)
}

pub fn jobs_from_args(args: &ArgMatches) -> CargoResult<Option<u32>> { //FIXME: validation
    let jobs = match args.value_of("jobs") {
        None => None,
        Some(jobs) => Some(jobs.parse::<u32>().map_err(|_| {
            clap::Error::value_validation_auto(
                format!("could not parse `{}` as a number", jobs)
            )
        })?)
    };
    Ok(jobs)
}

pub fn compile_options_from_args<'a>(
    config: &'a Config,
    args: &'a ArgMatches<'a>,
    mode: CompileMode,
) -> CargoResult<CompileOptions<'a>> {
    let spec = Packages::from_flags(
        args.is_present("all"),
        values(args, "exclude"),
        values(args, "package"),
    )?;

    let message_format = match args.value_of("message-format") {
        None => MessageFormat::Human,
        Some(f) => {
            if f.eq_ignore_ascii_case("json") {
                MessageFormat::Json
            } else if f.eq_ignore_ascii_case("human") {
                MessageFormat::Human
            } else {
                panic!("Impossible message format: {:?}", f)
            }
        }
    };

    let opts = CompileOptions {
        config,
        jobs: jobs_from_args(args)?,
        target: args.value_of("target"),
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        spec,
        mode,
        release: args.is_present("release"),
        filter: CompileFilter::new(args.is_present("lib"),
                                   values(args, "bin"), args.is_present("bins"),
                                   values(args, "test"), args.is_present("tests"),
                                   values(args, "example"), args.is_present("examples"),
                                   values(args, "bench"), args.is_present("benches"),
                                   args.is_present("all-targets")),
        message_format,
        target_rustdoc_args: None,
        target_rustc_args: None,
    };
    Ok(opts)
}

pub fn compile_options_from_args_for_single_package<'a>(
    config: &'a Config,
    args: &'a ArgMatches<'a>,
    mode: CompileMode,
) -> CargoResult<CompileOptions<'a>> {
    let mut compile_opts = compile_options_from_args(config, args, mode)?;
    compile_opts.spec = Packages::Packages(values(args, "package"));
    Ok(compile_opts)
}

pub fn new_opts_from_args<'a>(args: &'a ArgMatches<'a>, path: &'a str) -> CargoResult<NewOptions<'a>> {
    let vcs = args.value_of("vcs").map(|vcs| match vcs {
        "git" => VersionControl::Git,
        "hg" => VersionControl::Hg,
        "pijul" => VersionControl::Pijul,
        "fossil" => VersionControl::Fossil,
        "none" => VersionControl::NoVcs,
        vcs => panic!("Impossible vcs: {:?}", vcs),
    });
    NewOptions::new(vcs,
                    args.is_present("bin"),
                    args.is_present("lib"),
                    path,
                    args.value_of("name"))
}

pub fn registry_from_args(config: &Config, args: &ArgMatches) -> CargoResult<Option<String>> {
    match args.value_of("registry") {
        Some(registry) => {
            if !config.cli_unstable().unstable_options {
                return Err(format_err!("registry option is an unstable feature and \
                            requires -Zunstable-options to use.").into());
            }
            Ok(Some(registry.to_string()))
        }
        None => Ok(None),
    }
}

pub fn index_from_args(config: &Config, args: &ArgMatches) -> CargoResult<Option<String>> {
    // TODO: Deprecated
    // remove once it has been decided --host can be removed
    // We may instead want to repurpose the host flag, as
    // mentioned in this issue
    // https://github.com/rust-lang/cargo/issues/4208
    let msg = "The flag '--host' is no longer valid.

Previous versions of Cargo accepted this flag, but it is being
deprecated. The flag is being renamed to 'index', as the flag
wants the location of the index. Please use '--index' instead.

This will soon become a hard error, so it's either recommended
to update to a fixed version or contact the upstream maintainer
about this warning.";

    let index = match args.value_of("host") {
        Some(host) => {
            config.shell().warn(&msg)?;
            Some(host.to_string())
        }
        None => args.value_of("index").map(|s| s.to_string())
    };
    Ok(index)
}
<|endoftext|>