<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::io::{self, Cursor, Error, ErrorKind, Read, Seek, SeekFrom, Write};
use std::sync::{Arc, Mutex};
use std::{cmp, fmt};

use crate::file::writer::TryClone;

/// This is object to use if your file is already in memory.
/// The sliceable cursor is similar to std::io::Cursor, except that it makes it easy to create "cursor slices".
/// To achieve this, it uses Arc instead of shared references. Indeed reference fields are painfull
/// because the lack of Generic Associated Type implies that you would require complex lifetime propagation when
/// returning such a cursor.
#[allow(clippy::rc_buffer)]
pub struct SliceableCursor {
    inner: Arc<Vec<u8>>,
    start: u64,
    length: usize,
    pos: u64,
}

impl fmt::Debug for SliceableCursor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SliceableCursor")
            .field("start", &self.start)
            .field("length", &self.length)
            .field("pos", &self.pos)
            .field("inner.len", &self.inner.len())
            .finish()
    }
}

impl SliceableCursor {
    pub fn new(content: Vec<u8>) -> Self {
        let size = content.len();
        SliceableCursor {
            inner: Arc::new(content),
            start: 0,
            pos: 0,
            length: size,
        }
    }

    /// Create a slice cursor using the same data as a current one.
    pub fn slice(&self, start: u64, length: usize) -> io::Result<Self> {
        let new_start = self.start + start;
        if new_start >= self.inner.len() as u64
            || new_start as usize + length > self.inner.len()
        {
            return Err(Error::new(ErrorKind::InvalidInput, "out of bound"));
        }
        Ok(SliceableCursor {
            inner: Arc::clone(&self.inner),
            start: new_start,
            pos: new_start,
            length,
        })
    }

    fn remaining_slice(&self) -> &[u8] {
        let end = self.start as usize + self.length;
        let offset = cmp::min(self.pos, end as u64) as usize;
        &self.inner[offset..end]
    }

    /// Get the length of the current cursor slice
    pub fn len(&self) -> u64 {
        self.length as u64
    }

    /// return true if the cursor is empty (self.len() == 0)
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// Implementation inspired by std::io::Cursor
impl Read for SliceableCursor {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = Read::read(&mut self.remaining_slice(), buf)?;
        self.pos += n as u64;
        Ok(n)
    }
}

impl Seek for SliceableCursor {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        let new_pos = match pos {
            SeekFrom::Start(pos) => pos as i64,
            SeekFrom::End(pos) => self.inner.len() as i64 + pos as i64,
            SeekFrom::Current(pos) => self.pos as i64 + pos as i64,
        };

        if new_pos < 0 {
            Err(Error::new(
                ErrorKind::InvalidInput,
                format!(
                    "Request out of bounds: cur position {} + seek {:?} < 0: {}",
                    self.pos, pos, new_pos
                ),
            ))
        } else if new_pos >= self.inner.len() as i64 {
            Err(Error::new(
                ErrorKind::InvalidInput,
                format!(
                    "Request out of bounds: cur position {} + seek {:?} >= length {}: {}",
                    self.pos,
                    pos,
                    self.inner.len(),
                    new_pos
                ),
            ))
        } else {
            self.pos = new_pos as u64;
            Ok(self.start)
        }
    }
}

/// Use this type to write Parquet to memory rather than a file.
#[derive(Debug, Default, Clone)]
pub struct InMemoryWriteableCursor {
    buffer: Arc<Mutex<Cursor<Vec<u8>>>>,
}

impl InMemoryWriteableCursor {
    /// Consume this instance and return the underlying buffer as long as there are no other
    /// references to this instance.
    pub fn into_inner(self) -> Option<Vec<u8>> {
        Arc::try_unwrap(self.buffer)
            .ok()
            .and_then(|mutex| mutex.into_inner().ok())
            .map(|cursor| cursor.into_inner())
    }

    /// Returns a clone of the underlying buffer
    pub fn data(&self) -> Vec<u8> {
        let inner = self.buffer.lock().unwrap();
        inner.get_ref().to_vec()
    }
}

impl TryClone for InMemoryWriteableCursor {
    fn try_clone(&self) -> std::io::Result<Self> {
        Ok(Self {
            buffer: self.buffer.clone(),
        })
    }
}

impl Write for InMemoryWriteableCursor {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let mut inner = self.buffer.lock().unwrap();
        inner.write(buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        let mut inner = self.buffer.lock().unwrap();
        inner.flush()
    }
}

impl Seek for InMemoryWriteableCursor {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        let mut inner = self.buffer.lock().unwrap();
        inner.seek(pos)
    }
}

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

    /// Create a SliceableCursor of all u8 values in ascending order
    fn get_u8_range() -> SliceableCursor {
        let data: Vec<u8> = (0u8..=255).collect();
        SliceableCursor::new(data)
    }

    /// Reads all the bytes in the slice and checks that it matches the u8 range from start to end_included
    fn check_read_all(mut cursor: SliceableCursor, start: u8, end_included: u8) {
        let mut target = vec![];
        let cursor_res = cursor.read_to_end(&mut target);
        println!("{:?}", cursor_res);
        assert!(!cursor_res.is_err(), "reading error");
        assert_eq!((end_included - start) as usize + 1, cursor_res.unwrap());
        assert_eq!((start..=end_included).collect::<Vec<_>>(), target);
    }

    #[test]
    fn read_all_whole() {
        let cursor = get_u8_range();
        check_read_all(cursor, 0, 255);
    }

    #[test]
    fn read_all_slice() {
        let cursor = get_u8_range().slice(10, 10).expect("error while slicing");
        check_read_all(cursor, 10, 19);
    }

    #[test]
    fn seek_cursor_start() {
        let mut cursor = get_u8_range();

        cursor.seek(SeekFrom::Start(5)).unwrap();
        check_read_all(cursor, 5, 255);
    }

    #[test]
    fn seek_cursor_current() {
        let mut cursor = get_u8_range();
        cursor.seek(SeekFrom::Start(10)).unwrap();
        cursor.seek(SeekFrom::Current(10)).unwrap();
        check_read_all(cursor, 20, 255);
    }

    #[test]
    fn seek_cursor_end() {
        let mut cursor = get_u8_range();

        cursor.seek(SeekFrom::End(-10)).unwrap();
        check_read_all(cursor, 246, 255);
    }

    #[test]
    fn seek_cursor_error_too_long() {
        let mut cursor = get_u8_range();
        let res = cursor.seek(SeekFrom::Start(1000));
        let actual_error = res.expect_err("expected error").to_string();
        let expected_error =
            "Request out of bounds: cur position 0 + seek Start(1000) >= length 256: 1000";
        assert_eq!(actual_error, expected_error);
    }

    #[test]
    fn seek_cursor_error_too_short() {
        let mut cursor = get_u8_range();
        let res = cursor.seek(SeekFrom::End(-1000));
        let actual_error = res.expect_err("expected error").to_string();
        let expected_error =
            "Request out of bounds: cur position 0 + seek End(-1000) < 0: -744";
        assert_eq!(actual_error, expected_error);
    }
}
<commit_msg>ARROW-11592: [Rust] Fix typo in comment<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::io::{self, Cursor, Error, ErrorKind, Read, Seek, SeekFrom, Write};
use std::sync::{Arc, Mutex};
use std::{cmp, fmt};

use crate::file::writer::TryClone;

/// This is object to use if your file is already in memory.
/// The sliceable cursor is similar to std::io::Cursor, except that it makes it easy to create "cursor slices".
/// To achieve this, it uses Arc instead of shared references. Indeed reference fields are painful
/// because the lack of Generic Associated Type implies that you would require complex lifetime propagation when
/// returning such a cursor.
#[allow(clippy::rc_buffer)]
pub struct SliceableCursor {
    inner: Arc<Vec<u8>>,
    start: u64,
    length: usize,
    pos: u64,
}

impl fmt::Debug for SliceableCursor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SliceableCursor")
            .field("start", &self.start)
            .field("length", &self.length)
            .field("pos", &self.pos)
            .field("inner.len", &self.inner.len())
            .finish()
    }
}

impl SliceableCursor {
    pub fn new(content: Vec<u8>) -> Self {
        let size = content.len();
        SliceableCursor {
            inner: Arc::new(content),
            start: 0,
            pos: 0,
            length: size,
        }
    }

    /// Create a slice cursor using the same data as a current one.
    pub fn slice(&self, start: u64, length: usize) -> io::Result<Self> {
        let new_start = self.start + start;
        if new_start >= self.inner.len() as u64
            || new_start as usize + length > self.inner.len()
        {
            return Err(Error::new(ErrorKind::InvalidInput, "out of bound"));
        }
        Ok(SliceableCursor {
            inner: Arc::clone(&self.inner),
            start: new_start,
            pos: new_start,
            length,
        })
    }

    fn remaining_slice(&self) -> &[u8] {
        let end = self.start as usize + self.length;
        let offset = cmp::min(self.pos, end as u64) as usize;
        &self.inner[offset..end]
    }

    /// Get the length of the current cursor slice
    pub fn len(&self) -> u64 {
        self.length as u64
    }

    /// return true if the cursor is empty (self.len() == 0)
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// Implementation inspired by std::io::Cursor
impl Read for SliceableCursor {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = Read::read(&mut self.remaining_slice(), buf)?;
        self.pos += n as u64;
        Ok(n)
    }
}

impl Seek for SliceableCursor {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        let new_pos = match pos {
            SeekFrom::Start(pos) => pos as i64,
            SeekFrom::End(pos) => self.inner.len() as i64 + pos as i64,
            SeekFrom::Current(pos) => self.pos as i64 + pos as i64,
        };

        if new_pos < 0 {
            Err(Error::new(
                ErrorKind::InvalidInput,
                format!(
                    "Request out of bounds: cur position {} + seek {:?} < 0: {}",
                    self.pos, pos, new_pos
                ),
            ))
        } else if new_pos >= self.inner.len() as i64 {
            Err(Error::new(
                ErrorKind::InvalidInput,
                format!(
                    "Request out of bounds: cur position {} + seek {:?} >= length {}: {}",
                    self.pos,
                    pos,
                    self.inner.len(),
                    new_pos
                ),
            ))
        } else {
            self.pos = new_pos as u64;
            Ok(self.start)
        }
    }
}

/// Use this type to write Parquet to memory rather than a file.
#[derive(Debug, Default, Clone)]
pub struct InMemoryWriteableCursor {
    buffer: Arc<Mutex<Cursor<Vec<u8>>>>,
}

impl InMemoryWriteableCursor {
    /// Consume this instance and return the underlying buffer as long as there are no other
    /// references to this instance.
    pub fn into_inner(self) -> Option<Vec<u8>> {
        Arc::try_unwrap(self.buffer)
            .ok()
            .and_then(|mutex| mutex.into_inner().ok())
            .map(|cursor| cursor.into_inner())
    }

    /// Returns a clone of the underlying buffer
    pub fn data(&self) -> Vec<u8> {
        let inner = self.buffer.lock().unwrap();
        inner.get_ref().to_vec()
    }
}

impl TryClone for InMemoryWriteableCursor {
    fn try_clone(&self) -> std::io::Result<Self> {
        Ok(Self {
            buffer: self.buffer.clone(),
        })
    }
}

impl Write for InMemoryWriteableCursor {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let mut inner = self.buffer.lock().unwrap();
        inner.write(buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        let mut inner = self.buffer.lock().unwrap();
        inner.flush()
    }
}

impl Seek for InMemoryWriteableCursor {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        let mut inner = self.buffer.lock().unwrap();
        inner.seek(pos)
    }
}

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

    /// Create a SliceableCursor of all u8 values in ascending order
    fn get_u8_range() -> SliceableCursor {
        let data: Vec<u8> = (0u8..=255).collect();
        SliceableCursor::new(data)
    }

    /// Reads all the bytes in the slice and checks that it matches the u8 range from start to end_included
    fn check_read_all(mut cursor: SliceableCursor, start: u8, end_included: u8) {
        let mut target = vec![];
        let cursor_res = cursor.read_to_end(&mut target);
        println!("{:?}", cursor_res);
        assert!(!cursor_res.is_err(), "reading error");
        assert_eq!((end_included - start) as usize + 1, cursor_res.unwrap());
        assert_eq!((start..=end_included).collect::<Vec<_>>(), target);
    }

    #[test]
    fn read_all_whole() {
        let cursor = get_u8_range();
        check_read_all(cursor, 0, 255);
    }

    #[test]
    fn read_all_slice() {
        let cursor = get_u8_range().slice(10, 10).expect("error while slicing");
        check_read_all(cursor, 10, 19);
    }

    #[test]
    fn seek_cursor_start() {
        let mut cursor = get_u8_range();

        cursor.seek(SeekFrom::Start(5)).unwrap();
        check_read_all(cursor, 5, 255);
    }

    #[test]
    fn seek_cursor_current() {
        let mut cursor = get_u8_range();
        cursor.seek(SeekFrom::Start(10)).unwrap();
        cursor.seek(SeekFrom::Current(10)).unwrap();
        check_read_all(cursor, 20, 255);
    }

    #[test]
    fn seek_cursor_end() {
        let mut cursor = get_u8_range();

        cursor.seek(SeekFrom::End(-10)).unwrap();
        check_read_all(cursor, 246, 255);
    }

    #[test]
    fn seek_cursor_error_too_long() {
        let mut cursor = get_u8_range();
        let res = cursor.seek(SeekFrom::Start(1000));
        let actual_error = res.expect_err("expected error").to_string();
        let expected_error =
            "Request out of bounds: cur position 0 + seek Start(1000) >= length 256: 1000";
        assert_eq!(actual_error, expected_error);
    }

    #[test]
    fn seek_cursor_error_too_short() {
        let mut cursor = get_u8_range();
        let res = cursor.seek(SeekFrom::End(-1000));
        let actual_error = res.expect_err("expected error").to_string();
        let expected_error =
            "Request out of bounds: cur position 0 + seek End(-1000) < 0: -744";
        assert_eq!(actual_error, expected_error);
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Local, TimeZone, Utc};
use eyre::Result;
use stencila_schema::{Date, Node};

/// Decode a string into a `Node::Date` variant.
///
/// Always returns an `Ok` result with a `Node::Date` value
/// but its `value` may be `None`.
pub fn decode(input: &str) -> Result<Node> {
    Ok(Node::Date(decode_date(input)))
}

/// Decode a string to a `Date` struct.
///
/// If the string input could not be parsed as a date, will
/// return a date with an empty `value` string.
pub fn decode_date(input: &str) -> Date {
    if let Some(date) = decode_date_maybe(input) {
        date
    } else {
        Date {
            ..Default::default()
        }
    }
}

/// Attempt to decode a string to a `Date` struct.
///
/// Returns `Some(Date)` if parsing was successful, `None` otherwise.
pub fn decode_date_maybe(input: &str) -> Option<Date> {
    if let Ok((naive, offset)) = dtparse::parse(input) {
        let utc = match offset {
            Some(offset) => {
                let tz = offset.from_local_datetime(&naive).unwrap();
                DateTime::<Utc>::from(tz)
            }
            None => {
                let local = Local.from_local_datetime(&naive).unwrap();
                DateTime::<Utc>::from(local)
            }
        };
        Some(Date {
            value: utc.to_rfc3339(),
            ..Default::default()
        })
    } else {
        None
    }
}

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

    #[test]
    fn test_decoding() {
        assert_eq!(&decode_date("11 Jul 2021").value[..10], "2021-07-10");
        assert_eq!(&decode_date("11 July 2021").value[..10], "2021-07-10");
        assert_eq!(&decode_date("July 11 2021").value[..10], "2021-07-10");
        assert_eq!(&decode_date("2021-07-11").value[..10], "2021-07-10");
    }
}
<commit_msg>test(Date): Add timezone to avoid affect of different local time on test machines<commit_after>use chrono::{DateTime, Local, TimeZone, Utc};
use eyre::Result;
use stencila_schema::{Date, Node};

/// Decode a string into a `Node::Date` variant.
///
/// Always returns an `Ok` result with a `Node::Date` value
/// but its `value` may be `None`.
pub fn decode(input: &str) -> Result<Node> {
    Ok(Node::Date(decode_date(input)))
}

/// Decode a string to a `Date` struct.
///
/// If the string input could not be parsed as a date, will
/// return a date with an empty `value` string.
pub fn decode_date(input: &str) -> Date {
    if let Some(date) = decode_date_maybe(input) {
        date
    } else {
        Date {
            ..Default::default()
        }
    }
}

/// Attempt to decode a string to a `Date` struct.
///
/// Returns `Some(Date)` if parsing was successful, `None` otherwise.
pub fn decode_date_maybe(input: &str) -> Option<Date> {
    if let Ok((naive, offset)) = dtparse::parse(input) {
        let utc = match offset {
            Some(offset) => {
                let tz = offset.from_local_datetime(&naive).unwrap();
                DateTime::<Utc>::from(tz)
            }
            None => {
                let local = Local.from_local_datetime(&naive).unwrap();
                DateTime::<Utc>::from(local)
            }
        };
        Some(Date {
            value: utc.to_rfc3339(),
            ..Default::default()
        })
    } else {
        None
    }
}

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

    #[test]
    fn test_decoding() {
        // Adding timezone avoids failures due to different local time on
        // test host machines.
        assert_eq!(&decode_date("11 Jul 2021; 12 am +00:00").value, "2021-07-11T00:00:00+00:00");
        assert_eq!(&decode_date("July 11 2021; 6 am +06:00").value, "2021-07-11T00:00:00+00:00");
        assert_eq!(&decode_date("2021-07-11; 13:00 +13:00").value, "2021-07-11T00:00:00+00:00");
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::io::BufReader;
use std::fs::File;

use crate::types::*;
use serde_json;

use pombase_rc_string::RcString;

// configuration for extension display names and for the "Target of" section
#[derive(Deserialize, Clone, Debug)]
pub struct ExtensionDisplayNames {
    pub rel_name: RcString, // name of extension relation
    pub display_name: RcString, // text to display
    pub if_descendant_of: Option<RcString>, // None if applies to any extension
    pub reciprocal_display: Option<RcString>, // None if reciprocal shouldn't be displayed
}

// "interesting parents" are those stored in the JSON in the TermShort structs
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct InterestingParent {
    pub termid: RcString,
    pub rel_name: RcString,
}

// the order of relations within an extension:
#[derive(Deserialize, Clone, Debug)]
pub struct RelationOrder {
    // put the relations in this order in the displayed extensions:
    pub relation_order: Vec<RcString>,
    // except for these reactions which should always come last:
    pub always_last: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct AncestorFilterCategory {
    pub display_name: RcString,
    // this category matches these terms and their descendants
    pub ancestors: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FilterConfig {
    pub filter_name: String,
    pub display_name: String,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub term_categories: Vec<AncestorFilterCategory>,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub extension_categories: Vec<AncestorFilterCategory>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct SplitByParentsConfig {
    pub termids: Vec<RcString>,
    pub display_name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ChromosomeConfig {
    // string to use for this chromosome in a file name, eg. "chromosome_II"
    // or "mitochondrial_chromosome"
    pub export_file_id: RcString,
    // string to use within files, eg. "II" or "mitochondrial"
    pub export_id: RcString,
    // eg. "Chromosome II" or "Mitochondrial chromosome"
    pub long_display_name: RcString,
    // eg. "II" or "Mitochondrial"
    pub short_display_name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvSourceConfig {
    // a type name for the cvtermprop to display to the user
    pub display_name_prop: Option<RcString>,
    // the cvtermprop type name for the ID used for linking
    pub id_prop: Option<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvConfig {
    pub feature_type: RcString,
    // filtering configured per CV
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub filters: Vec<FilterConfig>,
    // config for splitting cv annotation tables into sub-sections
    // based on ancestry
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub split_by_parents: Vec<SplitByParentsConfig>,
    // relations to not show in the summary
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relations_to_hide: Vec<RcString>,
    // relations where the range is a gene ID to display like:
    //   has substrate pom1, cdc1 involved in negative regulation of ...
    // rather than as two lines
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relation_ranges_to_collect: Vec<RcString>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub sort_details_by: Option<Vec<RcString>>,

    // This is the configuration for the "Source" column, a map from
    // source name to config
    // See Disease association for an example.  If there is no config
    // there will be no Source column will be displayed
    #[serde(skip_serializing_if="HashMap::is_empty", default)]
    pub source_config: HashMap<RcString, CvSourceConfig>,
}

pub type ShortEvidenceCode = RcString;
pub type LongEvidenceCode = RcString;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct ConfigOrganism {
    pub taxonid: OrganismTaxonId,
    pub genus: RcString,
    pub species: RcString,
    pub assembly_version: Option<RcString>,
}

impl ConfigOrganism {
    pub fn full_name(&self) -> String {
        self.genus.clone() + "_" + self.species.as_str()
    }
}

#[derive(Deserialize, Clone, Debug)]
pub struct ViabilityTerms {
    pub viable: RcString,
    pub inviable: RcString,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct TermAndName {
    pub termid: RcString,
    pub name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ReferencePageConfig {
    pub triage_status_to_ignore: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct InterPro {
    pub dbnames_to_filter: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerSubsetConfig {
    pub prefixes_to_remove: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerConfig {
    pub subsets: ServerSubsetConfig,
    pub solr_url: String,
    pub close_synonym_boost: f32,
    pub distant_synonym_boost: f32,
    pub django_url: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct EvidenceDetails {
    pub long: LongEvidenceCode,
    pub link: Option<RcString>,
}

pub type DatabaseName = RcString;
pub type DatabaseAliases = HashMap<DatabaseName, DatabaseName>;

#[derive(Deserialize, Clone, Debug)]
pub struct QueryDataConfig {
    pub ortholog_presence_taxonids: HashSet<u32>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct MacromolecularComplexesConfig {
    pub parent_complex_termid: RcString,
    pub excluded_terms: HashSet<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct RNAcentralConfig {
    // SO termids of RNA features to export
    pub export_so_ids: HashSet<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FileExportConfig {
    #[serde(skip_serializing_if="Option::is_none")]
    pub macromolecular_complexes: Option<MacromolecularComplexesConfig>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub rnacentral: Option<RNAcentralConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisAttrValueConfig {
    pub termid: Option<RcString>,
    pub name: RcString,
    pub bin_start: Option<usize>,
    pub bin_end: Option<usize>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisColumnConfig {
    pub name: RcString,
    pub attr_values: Vec<GeneResultVisAttrValueConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisConfig {
    pub columns: Vec<GeneResultVisColumnConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultsConfig {
    pub visualisation: GeneResultVisConfig,
}

#[derive(Deserialize, Clone, Debug)]
pub struct SlimConfig {
    pub slim_display_name: RcString,
    pub terms: Vec<TermAndName>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Config {
    pub database_name: RcString,
    pub database_citation: RcString,
    pub load_organism_taxonid: Option<OrganismTaxonId>,
    pub base_url: RcString,
    pub organisms: Vec<ConfigOrganism>,
    pub api_seq_chunk_sizes: Vec<usize>,
    pub extension_display_names: Vec<ExtensionDisplayNames>,
    pub extension_relation_order: RelationOrder,
    pub evidence_types: HashMap<ShortEvidenceCode, EvidenceDetails>,
    pub cv_config: HashMap<CvName, CvConfig>,
// when creating a TermShort struct, for each of these termids if the term has
// an "interesting parent" using the given rel_name, we store it in the
// interesting_parents field of the TermShort
    pub interesting_parents: Vec<InterestingParent>,
    pub viability_terms: ViabilityTerms,
    // slim sets by slim name:
    pub slims: HashMap<RcString, SlimConfig>,
    pub reference_page_config: ReferencePageConfig,
    pub interpro: InterPro,
    pub server: ServerConfig,
    pub extra_database_aliases: DatabaseAliases,
    pub chromosomes: HashMap<RcString, ChromosomeConfig>,
    pub gene_results: GeneResultsConfig,
    pub query_data_config: QueryDataConfig,
    pub file_exports: FileExportConfig,
}

impl Config {

    pub fn read(config_file_name: &str) -> Config {
        let file = match File::open(config_file_name) {
            Ok(file) => file,
            Err(err) => {
                panic!("Failed to read {}: {}\n", config_file_name, err)
            }
        };
        let reader = BufReader::new(file);

        match serde_json::from_reader(reader) {
            Ok(config) => config,
            Err(err) => {
                panic!("failed to parse {}: {}", config_file_name, err)
            },
        }
    }

    pub fn cv_config_by_name(&self, cv_name: &str) -> CvConfig {
        if let Some(config) = self.cv_config.get(cv_name) {
            config.clone()
        } else {
            let empty_cv_config =
                CvConfig {
                    feature_type: "".into(),
                    filters: vec![],
                    split_by_parents: vec![],
                    summary_relations_to_hide: vec![],
                    summary_relation_ranges_to_collect: vec![],
                    sort_details_by: None,
                    source_config: HashMap::new(),
                };

            if cv_name.starts_with("extension:") {
                if cv_name.ends_with(":gene") {
                    CvConfig {
                        feature_type: "gene".into(),
                        ..empty_cv_config
                    }
                } else {
                    CvConfig {
                        feature_type: "genotype".into(),
                        ..empty_cv_config
                    }
                }
            } else {
                CvConfig {
                    feature_type: "gene".into(),
                    ..empty_cv_config
                }
            }
        }
    }

    pub fn load_organism(&self) -> Option<ConfigOrganism> {
        if let Some(load_organism_taxonid) = self.load_organism_taxonid {
            for org in &self.organisms {
                if org.taxonid == load_organism_taxonid {
                    return Some(org.clone());
                }
            }

            panic!("can't find configuration for load_organism_taxonid: {}",
                   load_organism_taxonid);
        } else {
            None
        }
    }

    pub fn find_chromosome_config<'a>(&'a self, chromosome_name: &str)
                                      -> &'a ChromosomeConfig
    {
        if let Some(ref chr_conf) = self.chromosomes.get(chromosome_name) {
            &chr_conf
        } else {
            panic!("can't find chromosome configuration for {}", &chromosome_name);
        }
    }
}

pub const POMBASE_ANN_EXT_TERM_CV_NAME: &str = "PomBase annotation extension terms";
pub const ANNOTATION_EXT_REL_PREFIX: &str = "annotation_extension_relation-";

pub const DB_NAME: &str = "PomBase";

pub enum FeatureRelAnnotationType {
    Interaction,
    Ortholog,
    Paralog,
}
pub struct FeatureRelConfig {
    pub rel_type_name: &'static str,
    pub annotation_type: FeatureRelAnnotationType,
}
pub const FEATURE_REL_CONFIGS: [FeatureRelConfig; 4] =
    [
        FeatureRelConfig {
            rel_type_name: "interacts_physically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "interacts_genetically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "orthologous_to",
            annotation_type: FeatureRelAnnotationType::Ortholog,
        },
        FeatureRelConfig {
            rel_type_name: "paralogous_to",
            annotation_type: FeatureRelAnnotationType::Paralog,
        },
    ];

// relations to use when copy annotation to parents (ie. adding the
// annotation of child terms to parents)
pub const DESCENDANT_REL_NAMES: [&str; 7] =
    ["is_a", "part_of", "regulates", "positively_regulates", "negatively_regulates",
     "has_part", "output_of"];
// only consider has_part relations for these ontologies:
pub const HAS_PART_CV_NAMES: [&str; 1] = ["fission_yeast_phenotype"];

// number of genes before (and after) to add to the gene_neighbourhood field
pub const GENE_NEIGHBOURHOOD_DISTANCE: usize = 5;

pub const TRANSCRIPT_FEATURE_TYPES: [&str; 8] =
    ["snRNA", "rRNA", "mRNA", "snoRNA", "ncRNA", "tRNA", "pseudogenic_transcript",
     "transcript"];
pub const TRANSCRIPT_PART_TYPES: [&str; 4] =
    ["five_prime_UTR", "exon", "pseudogenic_exon", "three_prime_UTR"];
// any feature with a type not in this list or in the two TRANSCRIPT lists above
// will be stored in the other_features map
pub const HANDLED_FEATURE_TYPES: [&str; 7] =
    ["gene", "pseudogene", "intron", "genotype", "allele", "chromosome", "polypeptide"];

<commit_msg>Add ortholog_taxonids to config<commit_after>use std::collections::{HashMap, HashSet};
use std::io::BufReader;
use std::fs::File;

use crate::types::*;
use serde_json;

use pombase_rc_string::RcString;

// configuration for extension display names and for the "Target of" section
#[derive(Deserialize, Clone, Debug)]
pub struct ExtensionDisplayNames {
    pub rel_name: RcString, // name of extension relation
    pub display_name: RcString, // text to display
    pub if_descendant_of: Option<RcString>, // None if applies to any extension
    pub reciprocal_display: Option<RcString>, // None if reciprocal shouldn't be displayed
}

// "interesting parents" are those stored in the JSON in the TermShort structs
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct InterestingParent {
    pub termid: RcString,
    pub rel_name: RcString,
}

// the order of relations within an extension:
#[derive(Deserialize, Clone, Debug)]
pub struct RelationOrder {
    // put the relations in this order in the displayed extensions:
    pub relation_order: Vec<RcString>,
    // except for these reactions which should always come last:
    pub always_last: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct AncestorFilterCategory {
    pub display_name: RcString,
    // this category matches these terms and their descendants
    pub ancestors: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FilterConfig {
    pub filter_name: String,
    pub display_name: String,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub term_categories: Vec<AncestorFilterCategory>,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub extension_categories: Vec<AncestorFilterCategory>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct SplitByParentsConfig {
    pub termids: Vec<RcString>,
    pub display_name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ChromosomeConfig {
    // string to use for this chromosome in a file name, eg. "chromosome_II"
    // or "mitochondrial_chromosome"
    pub export_file_id: RcString,
    // string to use within files, eg. "II" or "mitochondrial"
    pub export_id: RcString,
    // eg. "Chromosome II" or "Mitochondrial chromosome"
    pub long_display_name: RcString,
    // eg. "II" or "Mitochondrial"
    pub short_display_name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvSourceConfig {
    // a type name for the cvtermprop to display to the user
    pub display_name_prop: Option<RcString>,
    // the cvtermprop type name for the ID used for linking
    pub id_prop: Option<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvConfig {
    pub feature_type: RcString,
    // filtering configured per CV
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub filters: Vec<FilterConfig>,
    // config for splitting cv annotation tables into sub-sections
    // based on ancestry
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub split_by_parents: Vec<SplitByParentsConfig>,
    // relations to not show in the summary
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relations_to_hide: Vec<RcString>,
    // relations where the range is a gene ID to display like:
    //   has substrate pom1, cdc1 involved in negative regulation of ...
    // rather than as two lines
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relation_ranges_to_collect: Vec<RcString>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub sort_details_by: Option<Vec<RcString>>,

    // This is the configuration for the "Source" column, a map from
    // source name to config
    // See Disease association for an example.  If there is no config
    // there will be no Source column will be displayed
    #[serde(skip_serializing_if="HashMap::is_empty", default)]
    pub source_config: HashMap<RcString, CvSourceConfig>,
}

pub type ShortEvidenceCode = RcString;
pub type LongEvidenceCode = RcString;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct ConfigOrganism {
    pub taxonid: OrganismTaxonId,
    pub genus: RcString,
    pub species: RcString,
    pub assembly_version: Option<RcString>,
}

impl ConfigOrganism {
    pub fn full_name(&self) -> String {
        self.genus.clone() + "_" + self.species.as_str()
    }
}

#[derive(Deserialize, Clone, Debug)]
pub struct ViabilityTerms {
    pub viable: RcString,
    pub inviable: RcString,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct TermAndName {
    pub termid: RcString,
    pub name: RcString,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ReferencePageConfig {
    pub triage_status_to_ignore: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct InterPro {
    pub dbnames_to_filter: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerSubsetConfig {
    pub prefixes_to_remove: Vec<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerConfig {
    pub subsets: ServerSubsetConfig,
    pub solr_url: String,
    pub close_synonym_boost: f32,
    pub distant_synonym_boost: f32,
    pub django_url: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct EvidenceDetails {
    pub long: LongEvidenceCode,
    pub link: Option<RcString>,
}

pub type DatabaseName = RcString;
pub type DatabaseAliases = HashMap<DatabaseName, DatabaseName>;

#[derive(Deserialize, Clone, Debug)]
pub struct MacromolecularComplexesConfig {
    pub parent_complex_termid: RcString,
    pub excluded_terms: HashSet<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct RNAcentralConfig {
    // SO termids of RNA features to export
    pub export_so_ids: HashSet<RcString>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FileExportConfig {
    #[serde(skip_serializing_if="Option::is_none")]
    pub macromolecular_complexes: Option<MacromolecularComplexesConfig>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub rnacentral: Option<RNAcentralConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisAttrValueConfig {
    pub termid: Option<RcString>,
    pub name: RcString,
    pub bin_start: Option<usize>,
    pub bin_end: Option<usize>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisColumnConfig {
    pub name: RcString,
    pub attr_values: Vec<GeneResultVisAttrValueConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultVisConfig {
    pub columns: Vec<GeneResultVisColumnConfig>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct GeneResultsConfig {
    pub visualisation: GeneResultVisConfig,
}

#[derive(Deserialize, Clone, Debug)]
pub struct SlimConfig {
    pub slim_display_name: RcString,
    pub terms: Vec<TermAndName>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Config {
    pub database_name: RcString,
    pub database_citation: RcString,
    pub load_organism_taxonid: Option<OrganismTaxonId>,
    pub base_url: RcString,
    pub organisms: Vec<ConfigOrganism>,
    pub api_seq_chunk_sizes: Vec<usize>,
    pub extension_display_names: Vec<ExtensionDisplayNames>,
    pub extension_relation_order: RelationOrder,
    pub evidence_types: HashMap<ShortEvidenceCode, EvidenceDetails>,
    pub cv_config: HashMap<CvName, CvConfig>,
// when creating a TermShort struct, for each of these termids if the term has
// an "interesting parent" using the given rel_name, we store it in the
// interesting_parents field of the TermShort
    pub interesting_parents: Vec<InterestingParent>,
    pub viability_terms: ViabilityTerms,
    // slim sets by slim name:
    pub slims: HashMap<RcString, SlimConfig>,
    pub reference_page_config: ReferencePageConfig,
    pub interpro: InterPro,
    pub server: ServerConfig,
    pub extra_database_aliases: DatabaseAliases,
    pub chromosomes: HashMap<RcString, ChromosomeConfig>,
    pub gene_results: GeneResultsConfig,
    pub ortholog_taxonids: HashSet<u32>,
    pub file_exports: FileExportConfig,
}

impl Config {

    pub fn read(config_file_name: &str) -> Config {
        let file = match File::open(config_file_name) {
            Ok(file) => file,
            Err(err) => {
                panic!("Failed to read {}: {}\n", config_file_name, err)
            }
        };
        let reader = BufReader::new(file);

        match serde_json::from_reader(reader) {
            Ok(config) => config,
            Err(err) => {
                panic!("failed to parse {}: {}", config_file_name, err)
            },
        }
    }

    pub fn cv_config_by_name(&self, cv_name: &str) -> CvConfig {
        if let Some(config) = self.cv_config.get(cv_name) {
            config.clone()
        } else {
            let empty_cv_config =
                CvConfig {
                    feature_type: "".into(),
                    filters: vec![],
                    split_by_parents: vec![],
                    summary_relations_to_hide: vec![],
                    summary_relation_ranges_to_collect: vec![],
                    sort_details_by: None,
                    source_config: HashMap::new(),
                };

            if cv_name.starts_with("extension:") {
                if cv_name.ends_with(":gene") {
                    CvConfig {
                        feature_type: "gene".into(),
                        ..empty_cv_config
                    }
                } else {
                    CvConfig {
                        feature_type: "genotype".into(),
                        ..empty_cv_config
                    }
                }
            } else {
                CvConfig {
                    feature_type: "gene".into(),
                    ..empty_cv_config
                }
            }
        }
    }

    pub fn load_organism(&self) -> Option<ConfigOrganism> {
        if let Some(load_organism_taxonid) = self.load_organism_taxonid {
            for org in &self.organisms {
                if org.taxonid == load_organism_taxonid {
                    return Some(org.clone());
                }
            }

            panic!("can't find configuration for load_organism_taxonid: {}",
                   load_organism_taxonid);
        } else {
            None
        }
    }

    pub fn find_chromosome_config<'a>(&'a self, chromosome_name: &str)
                                      -> &'a ChromosomeConfig
    {
        if let Some(ref chr_conf) = self.chromosomes.get(chromosome_name) {
            &chr_conf
        } else {
            panic!("can't find chromosome configuration for {}", &chromosome_name);
        }
    }
}

pub const POMBASE_ANN_EXT_TERM_CV_NAME: &str = "PomBase annotation extension terms";
pub const ANNOTATION_EXT_REL_PREFIX: &str = "annotation_extension_relation-";

pub const DB_NAME: &str = "PomBase";

pub enum FeatureRelAnnotationType {
    Interaction,
    Ortholog,
    Paralog,
}
pub struct FeatureRelConfig {
    pub rel_type_name: &'static str,
    pub annotation_type: FeatureRelAnnotationType,
}
pub const FEATURE_REL_CONFIGS: [FeatureRelConfig; 4] =
    [
        FeatureRelConfig {
            rel_type_name: "interacts_physically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "interacts_genetically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "orthologous_to",
            annotation_type: FeatureRelAnnotationType::Ortholog,
        },
        FeatureRelConfig {
            rel_type_name: "paralogous_to",
            annotation_type: FeatureRelAnnotationType::Paralog,
        },
    ];

// relations to use when copy annotation to parents (ie. adding the
// annotation of child terms to parents)
pub const DESCENDANT_REL_NAMES: [&str; 7] =
    ["is_a", "part_of", "regulates", "positively_regulates", "negatively_regulates",
     "has_part", "output_of"];
// only consider has_part relations for these ontologies:
pub const HAS_PART_CV_NAMES: [&str; 1] = ["fission_yeast_phenotype"];

// number of genes before (and after) to add to the gene_neighbourhood field
pub const GENE_NEIGHBOURHOOD_DISTANCE: usize = 5;

pub const TRANSCRIPT_FEATURE_TYPES: [&str; 8] =
    ["snRNA", "rRNA", "mRNA", "snoRNA", "ncRNA", "tRNA", "pseudogenic_transcript",
     "transcript"];
pub const TRANSCRIPT_PART_TYPES: [&str; 4] =
    ["five_prime_UTR", "exon", "pseudogenic_exon", "three_prime_UTR"];
// any feature with a type not in this list or in the two TRANSCRIPT lists above
// will be stored in the other_features map
pub const HANDLED_FEATURE_TYPES: [&str; 7] =
    ["gene", "pseudogene", "intron", "genotype", "allele", "chromosome", "polypeptide"];

<|endoftext|>


<commit_before>use arrayvec::ArrayVec;
use itertools::structs::Zip;
use num::Integer;
use std::iter::{self, FromIterator};
use std::marker::PhantomData;
use std::mem;

use primitive::decompose::IntoVertices;

pub trait Topological: Sized {
    type Vertex: Clone;
}

pub trait Polygonal: Topological {}

pub trait Arity {
    const ARITY: usize;
}

pub trait MapVerticesInto<U>: Topological
where
    U: Clone,
{
    type Output: Topological<Vertex = U>;

    fn map_vertices_into<F>(self, f: F) -> Self::Output
    where
        F: FnMut(Self::Vertex) -> U;
}

pub trait MapVertices<T, U>: Sized
where
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U;
}

pub trait ZipVerticesInto {
    type Output: FromIterator<<Self::Output as Topological>::Vertex> + Topological;

    fn zip_vertices_into(self) -> Self::Output;
}

macro_rules! zip_vertices_into {
    (topology => $t:ident, geometries => ($($g:ident),*)) => (
        #[allow(non_snake_case)]
        impl<$($g: Clone),*> ZipVerticesInto for ($($t<$g>),*) {
            type Output = $t<($($g),*)>;

            fn zip_vertices_into(self) -> Self::Output {
                let ($($g,)*) = self;
                izip!($($g.into_vertices()),*).collect()
            }
        }
    );
}

pub trait Rotate {
    fn rotate(&mut self, n: isize);
}

impl<I, T, U, P, Q> MapVertices<T, U> for I
where
    I: Iterator<Item = P>,
    P: MapVerticesInto<U, Output = Q> + Topological<Vertex = T>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U,
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    input: I,
    f: F,
    phantom: PhantomData<(T, U)>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(input: I, f: F) -> Self {
        Map {
            input,
            f,
            phantom: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
where
    I: Iterator<Item = P>,
    F: FnMut(T) -> U,
    P: MapVerticesInto<U, Output = Q> + Topological<Vertex = T>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.input
            .next()
            .map(|topology| topology.map_vertices_into(&mut self.f))
    }
}

pub struct Edge<T> {
    pub a: T,
    pub b: T,
}

impl<T> Edge<T> {
    pub fn new(a: T, b: T) -> Self {
        Edge { a, b }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Edge::new(value.clone(), value)
    }
}

impl<T> Arity for Edge<T> {
    const ARITY: usize = 2;
}

impl<T> FromIterator<T> for Edge<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Edge::new(input.next().unwrap(), input.next().unwrap())
    }
}
zip_vertices_into!(topology => Edge, geometries => (A, B));
zip_vertices_into!(topology => Edge, geometries => (A, B, C));
zip_vertices_into!(topology => Edge, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Edge<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Edge<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Edge { a, b } = self;
        Edge::new(f(a), f(b))
    }
}

impl<T> Topological for Edge<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Rotate for Edge<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a, b, c }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Triangle::new(value.clone(), value.clone(), value)
    }
}

impl<T> Arity for Triangle<T> {
    const ARITY: usize = 3;
}

impl<T> FromIterator<T> for Triangle<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Triangle::new(
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
        )
    }
}
zip_vertices_into!(topology => Triangle, geometries => (A, B));
zip_vertices_into!(topology => Triangle, geometries => (A, B, C));
zip_vertices_into!(topology => Triangle, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Triangle<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Triangle<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Topological for Triangle<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Triangle<T> where T: Clone {}

impl<T> Rotate for Triangle<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, Self::ARITY as isize);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
        }
        else if n == 2 {
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad { a, b, c, d }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Quad::new(value.clone(), value.clone(), value.clone(), value)
    }
}

impl<T> Arity for Quad<T> {
    const ARITY: usize = 4;
}

impl<T> FromIterator<T> for Quad<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Quad::new(
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
        )
    }
}
zip_vertices_into!(topology => Quad, geometries => (A, B));
zip_vertices_into!(topology => Quad, geometries => (A, B, C));
zip_vertices_into!(topology => Quad, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Quad<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Quad<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Topological for Quad<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Quad<T> where T: Clone {}

impl<T> Rotate for Quad<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, Self::ARITY as isize);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
            mem::swap(&mut self.c, &mut self.d);
        }
        else if n == 2 {
            mem::swap(&mut self.a, &mut self.c);
            mem::swap(&mut self.b, &mut self.d);
        }
        else if n == 3 {
            mem::swap(&mut self.d, &mut self.c);
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T> From<Triangle<T>> for Polygon<T> {
    fn from(triangle: Triangle<T>) -> Self {
        Polygon::Triangle(triangle)
    }
}

impl<T> From<Quad<T>> for Polygon<T> {
    fn from(quad: Quad<T>) -> Self {
        Polygon::Quad(quad)
    }
}

impl<T> FromIterator<T> for Polygon<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        // Associated constants cannot be used in constant expressions, so the
        // size of the `ArrayVec` uses a literal instead of `Quad::<T>::ARITY`.
        let input = input
            .into_iter()
            .take(Quad::<T>::ARITY)
            .collect::<ArrayVec<[T; 4]>>();
        match input.len() {
            Quad::<T>::ARITY => Polygon::Quad(Quad::from_iter(input)),
            Triangle::<T>::ARITY => Polygon::Triangle(Triangle::from_iter(input)),
            _ => panic!(),
        }
    }
}
zip_vertices_into!(topology => Polygon, geometries => (A, B));
zip_vertices_into!(topology => Polygon, geometries => (A, B, C));
zip_vertices_into!(topology => Polygon, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Polygon<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Polygon<U>;

    fn map_vertices_into<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_vertices_into(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_vertices_into(f)),
        }
    }
}

impl<T> Topological for Polygon<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Polygon<T> where T: Clone {}

impl<T> Rotate for Polygon<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}

fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}

pub type ZipVertices<T> = iter::Map<
    Zip<T>,
    fn(<Zip<T> as Iterator>::Item) -> <<Zip<T> as Iterator>::Item as ZipVerticesInto>::Output,
>;

/// Zips the vertices and topologies from multiple iterators into a single
/// iterator.
///
/// This is useful for zipping different attributes of a primitive generator.
/// For example, it can be used to combine position, plane, and texture
/// coordinate data of a cube into a single topology stream.
///
/// # Examples
///
/// Create a topological stream of position and texture coordinate data for a
/// cube:
///
/// ```rust
/// # extern crate num;
/// # extern crate plexus;
/// # use plexus::R32;
/// use plexus::prelude::*;
/// use plexus::primitive::cube::Cube;
/// use plexus::primitive;
///
/// # use num::One;
/// # fn map_to_color(texture: &Duplet<R32>) -> Triplet<R32> {
/// #     Triplet(One::one(), One::one(), One::one())
/// # }
/// # fn main() {
/// let cube = Cube::new();
/// let polygons =
///     primitive::zip_vertices((cube.polygons_with_position(), cube.polygons_with_texture()))
///         .map_vertices(|(position, texture)| (position, texture, map_to_color(&texture)))
///         .triangulate()
///         .collect::<Vec<_>>();
/// # }
/// ```
pub fn zip_vertices<T, U>(tuple: U) -> ZipVertices<T>
where
    Zip<T>: From<U> + Iterator,
    <Zip<T> as Iterator>::Item: ZipVerticesInto,
{
    Zip::from(tuple).map(zip_vertices_into)
}

fn zip_vertices_into<T>(
    item: <Zip<T> as Iterator>::Item,
) -> <<Zip<T> as Iterator>::Item as ZipVerticesInto>::Output
where
    Zip<T>: Iterator,
    <Zip<T> as Iterator>::Item: ZipVerticesInto,
{
    item.zip_vertices_into()
}
<commit_msg>Use `impl Iterator` for `zip_vertices`.<commit_after>use arrayvec::ArrayVec;
use itertools::structs::Zip;
use num::Integer;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::mem;

use primitive::decompose::IntoVertices;

pub trait Topological: Sized {
    type Vertex: Clone;
}

pub trait Polygonal: Topological {}

pub trait Arity {
    const ARITY: usize;
}

pub trait MapVerticesInto<U>: Topological
where
    U: Clone,
{
    type Output: Topological<Vertex = U>;

    fn map_vertices_into<F>(self, f: F) -> Self::Output
    where
        F: FnMut(Self::Vertex) -> U;
}

pub trait MapVertices<T, U>: Sized
where
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U;
}

pub trait ZipVerticesInto {
    type Output: FromIterator<<Self::Output as Topological>::Vertex> + Topological;

    fn zip_vertices_into(self) -> Self::Output;
}

macro_rules! zip_vertices_into {
    (topology => $t:ident, geometries => ($($g:ident),*)) => (
        #[allow(non_snake_case)]
        impl<$($g: Clone),*> ZipVerticesInto for ($($t<$g>),*) {
            type Output = $t<($($g),*)>;

            fn zip_vertices_into(self) -> Self::Output {
                let ($($g,)*) = self;
                izip!($($g.into_vertices()),*).collect()
            }
        }
    );
}

pub trait Rotate {
    fn rotate(&mut self, n: isize);
}

impl<I, T, U, P, Q> MapVertices<T, U> for I
where
    I: Iterator<Item = P>,
    P: MapVerticesInto<U, Output = Q> + Topological<Vertex = T>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U,
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    input: I,
    f: F,
    phantom: PhantomData<(T, U)>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(input: I, f: F) -> Self {
        Map {
            input,
            f,
            phantom: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
where
    I: Iterator<Item = P>,
    F: FnMut(T) -> U,
    P: MapVerticesInto<U, Output = Q> + Topological<Vertex = T>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.input
            .next()
            .map(|topology| topology.map_vertices_into(&mut self.f))
    }
}

pub struct Edge<T> {
    pub a: T,
    pub b: T,
}

impl<T> Edge<T> {
    pub fn new(a: T, b: T) -> Self {
        Edge { a, b }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Edge::new(value.clone(), value)
    }
}

impl<T> Arity for Edge<T> {
    const ARITY: usize = 2;
}

impl<T> FromIterator<T> for Edge<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Edge::new(input.next().unwrap(), input.next().unwrap())
    }
}
zip_vertices_into!(topology => Edge, geometries => (A, B));
zip_vertices_into!(topology => Edge, geometries => (A, B, C));
zip_vertices_into!(topology => Edge, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Edge<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Edge<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Edge { a, b } = self;
        Edge::new(f(a), f(b))
    }
}

impl<T> Topological for Edge<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Rotate for Edge<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a, b, c }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Triangle::new(value.clone(), value.clone(), value)
    }
}

impl<T> Arity for Triangle<T> {
    const ARITY: usize = 3;
}

impl<T> FromIterator<T> for Triangle<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Triangle::new(
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
        )
    }
}
zip_vertices_into!(topology => Triangle, geometries => (A, B));
zip_vertices_into!(topology => Triangle, geometries => (A, B, C));
zip_vertices_into!(topology => Triangle, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Triangle<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Triangle<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Topological for Triangle<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Triangle<T> where T: Clone {}

impl<T> Rotate for Triangle<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, Self::ARITY as isize);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
        }
        else if n == 2 {
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad { a, b, c, d }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Quad::new(value.clone(), value.clone(), value.clone(), value)
    }
}

impl<T> Arity for Quad<T> {
    const ARITY: usize = 4;
}

impl<T> FromIterator<T> for Quad<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut input = input.into_iter();
        Quad::new(
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
            input.next().unwrap(),
        )
    }
}
zip_vertices_into!(topology => Quad, geometries => (A, B));
zip_vertices_into!(topology => Quad, geometries => (A, B, C));
zip_vertices_into!(topology => Quad, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Quad<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Quad<U>;

    fn map_vertices_into<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Topological for Quad<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Quad<T> where T: Clone {}

impl<T> Rotate for Quad<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, Self::ARITY as isize);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
            mem::swap(&mut self.c, &mut self.d);
        }
        else if n == 2 {
            mem::swap(&mut self.a, &mut self.c);
            mem::swap(&mut self.b, &mut self.d);
        }
        else if n == 3 {
            mem::swap(&mut self.d, &mut self.c);
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T> From<Triangle<T>> for Polygon<T> {
    fn from(triangle: Triangle<T>) -> Self {
        Polygon::Triangle(triangle)
    }
}

impl<T> From<Quad<T>> for Polygon<T> {
    fn from(quad: Quad<T>) -> Self {
        Polygon::Quad(quad)
    }
}

impl<T> FromIterator<T> for Polygon<T> {
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        // Associated constants cannot be used in constant expressions, so the
        // size of the `ArrayVec` uses a literal instead of `Quad::<T>::ARITY`.
        let input = input
            .into_iter()
            .take(Quad::<T>::ARITY)
            .collect::<ArrayVec<[T; 4]>>();
        match input.len() {
            Quad::<T>::ARITY => Polygon::Quad(Quad::from_iter(input)),
            Triangle::<T>::ARITY => Polygon::Triangle(Triangle::from_iter(input)),
            _ => panic!(),
        }
    }
}
zip_vertices_into!(topology => Polygon, geometries => (A, B));
zip_vertices_into!(topology => Polygon, geometries => (A, B, C));
zip_vertices_into!(topology => Polygon, geometries => (A, B, C, D));

impl<T, U> MapVerticesInto<U> for Polygon<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Polygon<U>;

    fn map_vertices_into<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_vertices_into(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_vertices_into(f)),
        }
    }
}

impl<T> Topological for Polygon<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Polygon<T> where T: Clone {}

impl<T> Rotate for Polygon<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}

fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}

/// Zips the vertices and topologies from multiple iterators into a single
/// iterator.
///
/// This is useful for zipping different attributes of a primitive generator.
/// For example, it can be used to combine position, plane, and texture
/// coordinate data of a cube into a single topology stream.
///
/// # Examples
///
/// Create a topological stream of position and texture coordinate data for a
/// cube:
///
/// ```rust
/// # extern crate num;
/// # extern crate plexus;
/// # use plexus::R32;
/// use plexus::prelude::*;
/// use plexus::primitive::cube::Cube;
/// use plexus::primitive;
///
/// # use num::One;
/// # fn map_uv_to_color(texture: &Duplet<R32>) -> Triplet<R32> {
/// #     Triplet(One::one(), One::one(), One::one())
/// # }
/// # fn main() {
/// let cube = Cube::new();
/// let polygons =
///     // Zip positions and texture coordinates into each vertex.
///     primitive::zip_vertices((cube.polygons_with_position(), cube.polygons_with_texture()))
///         .map_vertices(|(position, texture)| (position, texture, map_uv_to_color(&texture)))
///         .triangulate()
///         .collect::<Vec<_>>();
/// # }
/// ```
pub fn zip_vertices<T, U>(
    tuple: U,
) -> impl Iterator<Item = <<Zip<T> as Iterator>::Item as ZipVerticesInto>::Output>
where
    Zip<T>: From<U> + Iterator,
    <Zip<T> as Iterator>::Item: ZipVerticesInto,
{
    Zip::from(tuple).map(|item| item.zip_vertices_into())
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Anagrams

extern crate collections;

use std::str;
use collections::HashMap;
use std::io::File;
use std::io::BufferedReader;
use std::cmp;

fn sort_string(string: &str) -> ~str {
	let mut chars: ~[char] = string.chars().collect();
	chars.sort();
	str::from_chars(chars)
}

fn main () {
	let path = Path::new("resources/unixdict.txt");
	let mut file = BufferedReader::new(File::open(&path));

	let mut map: HashMap<~str, Vec<~str>> = HashMap::new();

	for line in file.lines() {
		let s = line.unwrap().trim().to_owned();
		map.insert_or_update_with(sort_string(s.clone()), vec!(s.clone()),
				   |_k, v| v.push(s.clone())
				);
	}

	let max_length = map.iter().fold(0, |s, (_k, v)| cmp::max(s, v.len()));

	for (_k, v) in map.iter() {
		if v.len() == max_length {
			for s in v.iter() {
				print!("{} ", *s)
			}
			println!("")
		}
	}
}
<commit_msg>Refactored anagrams.rs<commit_after>// Implements http://rosettacode.org/wiki/Anagrams

extern crate collections;

use collections::HashMap;
use std::str;
use std::io::{File, BufferedReader};
use std::cmp::max;

fn sort_string(string: &str) -> ~str {
	let mut chars: ~[char] = string.chars().collect();
	chars.sort();
	str::from_chars(chars)
}

// Returns groups of anagrams (each group consists of a vector containing the words)
fn get_anagrams<T: Reader>(mut reader: BufferedReader<T>) -> HashMap<~str, Vec<~str>> {
    let mut map: HashMap<~str, Vec<~str>> = HashMap::new();

    // Make groups of words according to the letters they contain
    // i.e. evil, live would be in the same group because they share the same letters
	for line in reader.lines() {
		let s = line.unwrap().trim().to_owned();
		map.insert_or_update_with(sort_string(s.clone()), vec!(s.clone()),
				   |_k, v| v.push(s.clone())
				);
	}

    map
}

// Returns the groups of anagrams that contain the most words in them
fn get_biggest_groups_anagrams(groups: &HashMap<~str, Vec<~str>>) -> HashMap<~str, Vec<~str>> {
    let max_length = groups.iter().fold(0, |s, (_, v)| max(s, v.len()));

    groups.iter().filter(|&(_, v)| v.len() == max_length).map(|(x, y)| (x.clone(), y.clone())).collect()
}

fn main () {
	let path = Path::new("resources/unixdict.txt");
	let reader = BufferedReader::new(File::open(&path));

	let map = get_anagrams(reader);
	let biggest_groups = get_biggest_groups_anagrams(&map);

	for (_, v) in biggest_groups.iter() {
        for s in v.iter() {
            print!("{} ", *s)
        }
        println!("")
	}
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate coreutils;

use std::io;
use std::io::{Write, BufRead, BufReader, Stderr};
use std::env;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::process::exit;

use coreutils::extra::{OptionalExt, WriteExt};

static MAN_PAGE: &'static str = r#"
    NAME
        grep - print lines matching a pattern
    SYNOPSIS
        wc [-h | --help] [-n --line-number] PATTERN [FILE...]
    DESCRIPTION
        grep searches the named input FILEs for lines containing a match to the given PATTERN. If no files are specified, grep searches the standard input. grep prints the matching lines.

    OPTIONS
        -h
        --help
            Print this manual page.

        -n
        --line-number
            Prefix each line of output with the line number of the match.
"#;

#[derive(Copy, Clone)]
struct Flags {
    line_numbers: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags { line_numbers: false }
    }
}

fn main() {
    let args = env::args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let stdin = io::stdin();
    let stdin = stdin.lock();

    let mut flags = Flags::new();
    let mut pattern = String::new();
    let mut files = Vec::with_capacity(args.len());
    for arg in args {
        if arg.starts_with("-") {
            match arg.as_str() {
                "-h" | "--help" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                },
                "-n" | "--line-number" => flags.line_numbers = true,
                _ => {
                    stderr.write(b"Unkown option: ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.write(b"\n").try(&mut stderr);
                    let _ = stderr.flush();
                    exit(1);
                }
            }
        } else if pattern.is_empty() {
            pattern = arg.clone();
        } else {
            match File::open(&Path::new(&arg)) {
                Ok(f) => files.push(f),
                Err(e) => {
                    stderr.write(b"Error opening ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.write(b": ").try(&mut stderr);
                    stderr.write(e.description().as_bytes()).try(&mut stderr);
                    stderr.write(b"\n").try(&mut stderr);
                    let _ = stderr.flush();
                    exit(1);
                }
            }
        }
    }

    if pattern.is_empty() {
        stderr.write_all(b"You must provide a pattern\n").try(&mut stderr);
        exit(1);
    }

    if files.is_empty() {
        do_simple_search(stdin, &pattern, &mut stdout, &mut stderr, flags);
    } else {
        for f in files {
            do_simple_search(BufReader::new(f), &pattern, &mut stdout, &mut stderr, flags);
        }
    }
}

fn do_simple_search<T: BufRead, O: Write + WriteExt>(reader: T, pattern: &str, out: &mut O, stderr: &mut Stderr, flags: Flags) {
    let mut line_num = 0;
    for result in reader.lines() {
        line_num += 1;
        if let Ok(line) = result {
            if line.contains(pattern) {
                if flags.line_numbers {
                    out.write_all((line_num.to_string() + ": ").as_bytes()).try(stderr);
                }
                out.writeln(line.as_bytes()).try(stderr);
            }
        }
    }
}
<commit_msg>Update grep.rs<commit_after>#![deny(warnings)]
extern crate coreutils;

use std::io;
use std::io::{Write, BufRead, BufReader, Stderr};
use std::env;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::process::exit;

use coreutils::extra::{OptionalExt, WriteExt};

static MAN_PAGE: &'static str = r#"
    NAME
        grep - print lines matching a pattern
    SYNOPSIS
        grep [-h | --help] [-n --line-number] PATTERN [FILE...]
    DESCRIPTION
        grep searches the named input FILEs for lines containing a match to the given PATTERN. If no files are specified, grep searches the standard input. grep prints the matching lines.

    OPTIONS
        -h
        --help
            Print this manual page.

        -n
        --line-number
            Prefix each line of output with the line number of the match.
"#;

#[derive(Copy, Clone)]
struct Flags {
    line_numbers: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags { line_numbers: false }
    }
}

fn main() {
    let args = env::args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let stdin = io::stdin();
    let stdin = stdin.lock();

    let mut flags = Flags::new();
    let mut pattern = String::new();
    let mut files = Vec::with_capacity(args.len());
    for arg in args {
        if arg.starts_with("-") {
            match arg.as_str() {
                "-h" | "--help" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                },
                "-n" | "--line-number" => flags.line_numbers = true,
                _ => {
                    stderr.write(b"Unkown option: ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.write(b"\n").try(&mut stderr);
                    let _ = stderr.flush();
                    exit(1);
                }
            }
        } else if pattern.is_empty() {
            pattern = arg.clone();
        } else {
            match File::open(&Path::new(&arg)) {
                Ok(f) => files.push(f),
                Err(e) => {
                    stderr.write(b"Error opening ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.write(b": ").try(&mut stderr);
                    stderr.write(e.description().as_bytes()).try(&mut stderr);
                    stderr.write(b"\n").try(&mut stderr);
                    let _ = stderr.flush();
                    exit(1);
                }
            }
        }
    }

    if pattern.is_empty() {
        stderr.write_all(b"You must provide a pattern\n").try(&mut stderr);
        exit(1);
    }

    if files.is_empty() {
        do_simple_search(stdin, &pattern, &mut stdout, &mut stderr, flags);
    } else {
        for f in files {
            do_simple_search(BufReader::new(f), &pattern, &mut stdout, &mut stderr, flags);
        }
    }
}

fn do_simple_search<T: BufRead, O: Write + WriteExt>(reader: T, pattern: &str, out: &mut O, stderr: &mut Stderr, flags: Flags) {
    let mut line_num = 0;
    for result in reader.lines() {
        line_num += 1;
        if let Ok(line) = result {
            if line.contains(pattern) {
                if flags.line_numbers {
                    out.write_all((line_num.to_string() + ": ").as_bytes()).try(stderr);
                }
                out.writeln(line.as_bytes()).try(stderr);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::ascii::AsciiExt;
use std::env::args;
use std::io::{self, Write, Read};
use std::process::exit;

use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

static HELP: &'static str = /* @MANSTART{mtxt} */ r#"
NAME
    mtxt - a simple tool to manipulate text from standard input.

SYNOPSIS
    mtxt [-h | --help | -u | --to-uppercase-w | -l | --to-lowercase | -a | --strip-non-ascii]

DESCRIPTION
    This utility will manipulate UTF-8 encoded text from the standard input. Unicode is supported.
    The flags are composable, unless otherwise stated.

OPTIONS
    -h
    --help
        Print this manual page.

    -u
    --to-uppercase
        Convert the input to UPPERCASE. Works correctly with Unicode. Incompatible with '-l'.

    -l
    --lowercase
        Convert the input to lowercase. Works correctly with Unicode.

    -a
    --strip-non-ascii
        Strip the input for non-ASCII bytes, outputting a valid ASCII string.

EXAMPLES
    $ echo Δ | mtxt -l
    > δ
    $ echo we got deltas Δ right | mtxt -a
    > we got deltas  right
    $ echo Japanese scripts do not have case thus 山will stay unchanged | mtxt -u
    > JAPANESE SCRIPTS DO NOT HAVE CASE THUS 山WILL STAY UNCHANGED

AUTHOR
    This program was written by Ticki for Redox OS. Bugs, issues, or feature requests should be
    reported in the Github repository, 'redox-os/extrautils'.

COPYRIGHT
    Copyright (c) 2016 Ticki

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or
    substantial portions of the Software.

    Do you actually read the license? wat?
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#; /* @MANEND */

fn main() {
    let stdin = io::stdin();
    let stdin = stdin.lock();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();

    // These are the options.
    let mut to_uppercase = false;
    let mut to_lowercase = false;
    let mut strip_non_ascii = false;

    for arg in args().skip(1) {
        match arg.as_str() {
            "-u" | "--to-uppercase" => to_uppercase = true,
            "-l" | "--to-lowercase" => to_lowercase = true,
            "-a" | "--strip-non-ascii" => strip_non_ascii = true,
            "-h" | "--help" => {
                // The help page.
                stdout.write(HELP.as_bytes()).try(&mut stderr);
            },
            a => {
                // The argument, a, is unknown.
                stderr.write(b"error: unknown argument, ").try(&mut stderr);
                stderr.write(a.as_bytes()).try(&mut stderr);
                stderr.write(b".\n").try(&mut stderr);
                stderr.flush().try(&mut stderr);
                exit(1);
            },
        }
    }

    if to_lowercase && to_uppercase {
        // Fail, since -u and -l are incompatible.
        fail("-u and -l are incompatible. Aborting.", &mut stderr);
    }

    // My eyes bleed.
    //
    // Anyone?
    // ...
    //
    // Silence.
    //
    // If you see this, rewrite the code below. Now, you can't say no. Too late.
    // Muhahahaha.
    for i in stdin.chars() {
        let i = i.try(&mut stderr);

        // TODO handle -a more efficient

        // If -u is set, convert to uppercase
        if to_uppercase {
            for uppercase in i.to_uppercase().filter(|x| !strip_non_ascii || x.is_ascii() ) {
                stdout.write_char(uppercase).try(&mut stderr);
            }
        // If -l is set, convert to lowercase
        } else if to_lowercase {
            for lowercase in i.to_lowercase().filter(|x| !strip_non_ascii || x.is_ascii()) {
                stdout.write_char(lowercase).try(&mut stderr);
            }
        // If -a is set, strip non-ASCII.
        } else if !strip_non_ascii || strip_non_ascii && i.is_ascii() {
            stdout.write_char(i).try(&mut stderr);
        }
    }
}
<commit_msg>Fix compile on linux<commit_after>#![deny(warnings)]
#![feature(io)]

extern crate extra;

use std::ascii::AsciiExt;
use std::env::args;
use std::io::{self, Write, Read};
use std::process::exit;

use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

static HELP: &'static str = /* @MANSTART{mtxt} */ r#"
NAME
    mtxt - a simple tool to manipulate text from standard input.

SYNOPSIS
    mtxt [-h | --help | -u | --to-uppercase-w | -l | --to-lowercase | -a | --strip-non-ascii]

DESCRIPTION
    This utility will manipulate UTF-8 encoded text from the standard input. Unicode is supported.
    The flags are composable, unless otherwise stated.

OPTIONS
    -h
    --help
        Print this manual page.

    -u
    --to-uppercase
        Convert the input to UPPERCASE. Works correctly with Unicode. Incompatible with '-l'.

    -l
    --lowercase
        Convert the input to lowercase. Works correctly with Unicode.

    -a
    --strip-non-ascii
        Strip the input for non-ASCII bytes, outputting a valid ASCII string.

EXAMPLES
    $ echo Δ | mtxt -l
    > δ
    $ echo we got deltas Δ right | mtxt -a
    > we got deltas  right
    $ echo Japanese scripts do not have case thus 山will stay unchanged | mtxt -u
    > JAPANESE SCRIPTS DO NOT HAVE CASE THUS 山WILL STAY UNCHANGED

AUTHOR
    This program was written by Ticki for Redox OS. Bugs, issues, or feature requests should be
    reported in the Github repository, 'redox-os/extrautils'.

COPYRIGHT
    Copyright (c) 2016 Ticki

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or
    substantial portions of the Software.

    Do you actually read the license? wat?
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#; /* @MANEND */

fn main() {
    let stdin = io::stdin();
    let stdin = stdin.lock();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();

    // These are the options.
    let mut to_uppercase = false;
    let mut to_lowercase = false;
    let mut strip_non_ascii = false;

    for arg in args().skip(1) {
        match arg.as_str() {
            "-u" | "--to-uppercase" => to_uppercase = true,
            "-l" | "--to-lowercase" => to_lowercase = true,
            "-a" | "--strip-non-ascii" => strip_non_ascii = true,
            "-h" | "--help" => {
                // The help page.
                stdout.write(HELP.as_bytes()).try(&mut stderr);
            },
            a => {
                // The argument, a, is unknown.
                stderr.write(b"error: unknown argument, ").try(&mut stderr);
                stderr.write(a.as_bytes()).try(&mut stderr);
                stderr.write(b".\n").try(&mut stderr);
                stderr.flush().try(&mut stderr);
                exit(1);
            },
        }
    }

    if to_lowercase && to_uppercase {
        // Fail, since -u and -l are incompatible.
        fail("-u and -l are incompatible. Aborting.", &mut stderr);
    }

    // My eyes bleed.
    //
    // Anyone?
    // ...
    //
    // Silence.
    //
    // If you see this, rewrite the code below. Now, you can't say no. Too late.
    // Muhahahaha.
    for i in stdin.chars() {
        let i = i.try(&mut stderr);

        // TODO handle -a more efficient

        // If -u is set, convert to uppercase
        if to_uppercase {
            for uppercase in i.to_uppercase().filter(|x| !strip_non_ascii || x.is_ascii() ) {
                stdout.write_char(uppercase).try(&mut stderr);
            }
        // If -l is set, convert to lowercase
        } else if to_lowercase {
            for lowercase in i.to_lowercase().filter(|x| !strip_non_ascii || x.is_ascii()) {
                stdout.write_char(lowercase).try(&mut stderr);
            }
        // If -a is set, strip non-ASCII.
        } else if !strip_non_ascii || strip_non_ascii && i.is_ascii() {
            stdout.write_char(i).try(&mut stderr);
        }
    }
}
<|endoftext|>


<commit_before>use libc;
use std::ptr;
use std::ffi::CStr;
use constants::*;
use ffi::{cs_close, cs_open, cs_disasm, cs_reg_name, cs_insn_name};
use instruction::{Insn, Instructions};

pub struct Capstone {
    csh: csh, // Opaque handle to cs_engine
}

impl Capstone {
    pub fn new(arch: CsArch, mode: CsMode) -> Option<Capstone> {
        let mut handle = 0;
        if let CsErr::CS_ERR_OK = unsafe { cs_open(arch, mode, &mut handle) } {
            Some(Capstone { csh: handle })
        } else {
            None
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: isize) -> Option<Instructions> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      code.as_ptr(),
                      code.len() as libc::size_t,
                      addr,
                      count as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            // TODO  On failure, call cs_errno() for error code.
            return None;
        }

        Some(Instructions::from_raw_parts(ptr, insn_count as isize))
    }

    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::size_t);
            if _reg_name == ptr::null() {
                return None;
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    pub fn insn_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_insn_name(self.csh, reg_id as libc::size_t);
            if _reg_name == ptr::null() {
                return None;
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<commit_msg>Add csh back<commit_after>use libc;
use std::ptr;
use std::ffi::CStr;
use constants::*;
use csh;
use ffi::{cs_close, cs_open, cs_disasm, cs_reg_name, cs_insn_name};
use instruction::{Insn, Instructions};

pub struct Capstone {
    csh: csh, // Opaque handle to cs_engine
}

impl Capstone {
    pub fn new(arch: CsArch, mode: CsMode) -> Option<Capstone> {
        let mut handle = 0;
        if let CsErr::CS_ERR_OK = unsafe { cs_open(arch, mode, &mut handle) } {
            Some(Capstone { csh: handle })
        } else {
            None
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: isize) -> Option<Instructions> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      code.as_ptr(),
                      code.len() as libc::size_t,
                      addr,
                      count as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            // TODO  On failure, call cs_errno() for error code.
            return None;
        }

        Some(Instructions::from_raw_parts(ptr, insn_count as isize))
    }

    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::size_t);
            if _reg_name == ptr::null() {
                return None;
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    pub fn insn_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_insn_name(self.csh, reg_id as libc::size_t);
            if _reg_name == ptr::null() {
                return None;
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<|endoftext|>