<commit_before>use std::iter::Iterator;

use self::SequenceItem::{Number, Range, Wildcard};

/// This represents an individual item in the list of requested message ids
/// passed by the client
/// The client can pass a number representing a single id, a wildcard
/// (represented by *) or a range which is made up of a start non-range sequence
/// item and an end non-range sequence item separated by a colon
/// A range represents all items with ids between its start and end, inclusive.
#[derive(Clone, PartialEq, Debug)]
pub enum SequenceItem {
    Number(usize),
    Range(Box<SequenceItem>, Box<SequenceItem>),
    Wildcard
}

fn parse_item(item: &str) -> Option<SequenceItem> {
    let intseq_opt: Option<usize> = item.parse();
    match intseq_opt {
        Ok(intseq) => {
            // item is a valid number so return that
            Some(Number(intseq))
        }
        Err(_) => {
            // item is not a valid number
            // If it is the wildcard value return that
            // Otherwise, return no sequence item
            if item == "*" {
                Some(Wildcard)
            } else {
                None
            }
        }
    }
}

/// Given a string as passed in from the client, create a list of sequence items
/// If the string does not represent a valid list, return None
pub fn parse(sequence_string: &str) -> Option<Vec<SequenceItem>> {
    let mut sequences = sequence_string.split(',');
    let mut sequence_set = Vec::new();
    for sequence in sequences {
        let mut range = sequence.split(':');
        let start = match range.next() {
            None => return None,
            Some(seq) => {
                match parse_item(seq) {
                    None => return None,
                    Some(item) => item
                }
            }
        };
        let stop = match range.next() {
            None => {
                // Nothing after ':'
                // Add the number or wildcard and bail out
                sequence_set.push(start);
                continue;
            }
            Some(seq) => {
                match parse_item(seq) {
                    None => return None,
                    Some(item) => item
                }
            }
        };

        // A valid range only has one colon
        match range.next() {
            Some(_) => return None,
            _ => {}
        }

        sequence_set.push(Range(Box::new(start), Box::new(stop)));
    }
    return Some(sequence_set);
}

/// Create the list of unsigned integers representing valid ids from a list of
/// sequence items. Ideally this would handle wildcards in O(1) rather than O(n)
pub fn iterator(sequence_set: &Vec<SequenceItem>, max_id: usize) -> Vec<usize> {
    // If the number of possible messages is 0, we return an empty vec.
    if max_id == 0 { return Vec::new() }

    let stop = max_id + 1;

    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            // For a number we just need the value
            &Number(num) => { items.push(num) },
            // For a range we need all the values inside it
            &Range(ref a, ref b) => {
                // Grab the start of the range
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                // Grab the end of the range
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                // Figure out which way the range points
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }

                // Bounds checks
                if min > stop { min = stop; }
                if max > stop { max = stop; }

                // Generate the list of values between the min and max
                let seq_range: Vec<usize> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            &Wildcard => {
                // If the sequence set contains the wildcard operator, it spans
                // the entire possible range of messages.
                return range(1, stop).collect()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    let items: Vec<usize> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

pub fn uid_iterator(sequence_set: &Vec<SequenceItem>) -> Vec<usize> {
    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            &Number(num) => { items.push(num) },
            &Range(ref a, ref b) => {
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { return Vec::new() }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { return Vec::new() }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }
                //if min > stop { min = stop; }
                //if max > stop { max = stop; }
                let seq_range: Vec<usize> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            &Wildcard => {
                return Vec::new()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    //let items: Vec<usize> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

#[test]
fn test_sequence_num() {
    assert_eq!(iterator(&vec![Number(4324)], 5000), vec![4324]);
    assert_eq!(iterator(&vec![Number(23), Number(44)], 5000), vec![23, 44]);
    assert_eq!(iterator(&vec![Number(6), Number(6), Number(2)], 5000), vec![2, 6]);
}

#[test]
fn test_sequence_past_end() {
    assert_eq!(iterator(&vec![Number(4324)], 100), Vec::new());
    assert_eq!(iterator(&vec![Number(23), Number(44)], 30), vec![23]);
    assert_eq!(iterator(&vec![Number(6), Number(6), Number(2)], 4), vec![2]);
}

#[test]
fn test_sequence_range() {
    assert_eq!(iterator(&vec![Range(Box::new(Number(6)), Box::new(Wildcard))], 10), vec![6, 7, 8, 9, 10]);
    assert_eq!(iterator(&vec![Range(Box::new(Number(1)), Box::new(Number(10)))], 4), vec![1, 2, 3, 4]);
    assert_eq!(iterator(&vec![Range(Box::new(Wildcard), Box::new(Number(8))), Number(9), Number(2), Number(2)], 12), vec![2, 8, 9, 10, 11, 12]);
}

#[test]
fn test_sequence_wildcard() {
    assert_eq!(iterator(&vec![Range(Box::new(Number(10)), Box::new(Wildcard)), Wildcard], 6), vec![1, 2, 3, 4, 5, 6]);
    assert_eq!(iterator(&vec![Wildcard, Number(8)], 3), vec![1, 2, 3]);
}

#[test]
fn test_sequence_complex() {
    assert_eq!(iterator(
            &vec![Number(1), Number(3), Range(Box::new(Number(5)), Box::new(Number(7))), Number(9), Number(12), Range(Box::new(Number(15)), Box::new(Wildcard))], 13),
            vec![1, 3, 5, 6, 7, 9, 12, 13]);
}
<commit_msg>Remove unnecessary type annotation<commit_after>use std::iter::Iterator;

use self::SequenceItem::{Number, Range, Wildcard};

/// This represents an individual item in the list of requested message ids
/// passed by the client
/// The client can pass a number representing a single id, a wildcard
/// (represented by *) or a range which is made up of a start non-range sequence
/// item and an end non-range sequence item separated by a colon
/// A range represents all items with ids between its start and end, inclusive.
#[derive(Clone, PartialEq, Debug)]
pub enum SequenceItem {
    Number(usize),
    Range(Box<SequenceItem>, Box<SequenceItem>),
    Wildcard
}

fn parse_item(item: &str) -> Option<SequenceItem> {
    let intseq_opt = item.parse();
    match intseq_opt {
        Ok(intseq) => {
            // item is a valid number so return that
            Some(Number(intseq))
        }
        Err(_) => {
            // item is not a valid number
            // If it is the wildcard value return that
            // Otherwise, return no sequence item
            if item == "*" {
                Some(Wildcard)
            } else {
                None
            }
        }
    }
}

/// Given a string as passed in from the client, create a list of sequence items
/// If the string does not represent a valid list, return None
pub fn parse(sequence_string: &str) -> Option<Vec<SequenceItem>> {
    let mut sequences = sequence_string.split(',');
    let mut sequence_set = Vec::new();
    for sequence in sequences {
        let mut range = sequence.split(':');
        let start = match range.next() {
            None => return None,
            Some(seq) => {
                match parse_item(seq) {
                    None => return None,
                    Some(item) => item
                }
            }
        };
        let stop = match range.next() {
            None => {
                // Nothing after ':'
                // Add the number or wildcard and bail out
                sequence_set.push(start);
                continue;
            }
            Some(seq) => {
                match parse_item(seq) {
                    None => return None,
                    Some(item) => item
                }
            }
        };

        // A valid range only has one colon
        match range.next() {
            Some(_) => return None,
            _ => {}
        }

        sequence_set.push(Range(Box::new(start), Box::new(stop)));
    }
    return Some(sequence_set);
}

/// Create the list of unsigned integers representing valid ids from a list of
/// sequence items. Ideally this would handle wildcards in O(1) rather than O(n)
pub fn iterator(sequence_set: &Vec<SequenceItem>, max_id: usize) -> Vec<usize> {
    // If the number of possible messages is 0, we return an empty vec.
    if max_id == 0 { return Vec::new() }

    let stop = max_id + 1;

    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            // For a number we just need the value
            &Number(num) => { items.push(num) },
            // For a range we need all the values inside it
            &Range(ref a, ref b) => {
                // Grab the start of the range
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                // Grab the end of the range
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                // Figure out which way the range points
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }

                // Bounds checks
                if min > stop { min = stop; }
                if max > stop { max = stop; }

                // Generate the list of values between the min and max
                let seq_range: Vec<usize> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            &Wildcard => {
                // If the sequence set contains the wildcard operator, it spans
                // the entire possible range of messages.
                return range(1, stop).collect()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    let items: Vec<usize> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

pub fn uid_iterator(sequence_set: &Vec<SequenceItem>) -> Vec<usize> {
    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            &Number(num) => { items.push(num) },
            &Range(ref a, ref b) => {
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { return Vec::new() }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { return Vec::new() }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }
                //if min > stop { min = stop; }
                //if max > stop { max = stop; }
                let seq_range: Vec<usize> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            &Wildcard => {
                return Vec::new()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    //let items: Vec<usize> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

#[test]
fn test_sequence_num() {
    assert_eq!(iterator(&vec![Number(4324)], 5000), vec![4324]);
    assert_eq!(iterator(&vec![Number(23), Number(44)], 5000), vec![23, 44]);
    assert_eq!(iterator(&vec![Number(6), Number(6), Number(2)], 5000), vec![2, 6]);
}

#[test]
fn test_sequence_past_end() {
    assert_eq!(iterator(&vec![Number(4324)], 100), Vec::new());
    assert_eq!(iterator(&vec![Number(23), Number(44)], 30), vec![23]);
    assert_eq!(iterator(&vec![Number(6), Number(6), Number(2)], 4), vec![2]);
}

#[test]
fn test_sequence_range() {
    assert_eq!(iterator(&vec![Range(Box::new(Number(6)), Box::new(Wildcard))], 10), vec![6, 7, 8, 9, 10]);
    assert_eq!(iterator(&vec![Range(Box::new(Number(1)), Box::new(Number(10)))], 4), vec![1, 2, 3, 4]);
    assert_eq!(iterator(&vec![Range(Box::new(Wildcard), Box::new(Number(8))), Number(9), Number(2), Number(2)], 12), vec![2, 8, 9, 10, 11, 12]);
}

#[test]
fn test_sequence_wildcard() {
    assert_eq!(iterator(&vec![Range(Box::new(Number(10)), Box::new(Wildcard)), Wildcard], 6), vec![1, 2, 3, 4, 5, 6]);
    assert_eq!(iterator(&vec![Wildcard, Number(8)], 3), vec![1, 2, 3]);
}

#[test]
fn test_sequence_complex() {
    assert_eq!(iterator(
            &vec![Number(1), Number(3), Range(Box::new(Number(5)), Box::new(Number(7))), Number(9), Number(12), Range(Box::new(Number(15)), Box::new(Wildcard))], 13),
            vec![1, 3, 5, 6, 7, 9, 12, 13]);
}
<|endoftext|>


<commit_before>use expression::{Expression, SelectableExpression, NonAggregate};
use persistable::{AsBindParam, InsertableColumns};
use row::Row;
use std::error::Error;
use types::{NativeSqlType, FromSqlRow, ValuesToSql, Nullable};
use {Queriable, Table, Column, QuerySource};

// FIXME(https://github.com/rust-lang/rust/issues/19630) Remove this work-around
macro_rules! e {
    ($e:expr) => { $e }
}

macro_rules! tuple_impls {
    ($(
        $Tuple:tt {
            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
        }
    )+) => {
        $(
            impl<$($T:NativeSqlType),+> NativeSqlType for ($($T,)+) {}

            impl<$($T),+,$($ST),+> FromSqlRow<($($ST),+)> for ($($T),+) where
                $($T: FromSqlRow<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn build_from_row<T: Row>(row: &mut T) -> Result<Self, Box<Error>> {
                    Ok(($(try!($T::build_from_row(row))),+))
                }
            }

            impl<$($T),+,$($ST),+> FromSqlRow<Nullable<($($ST),+)>> for Option<($($T),+)> where
                $($T: FromSqlRow<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn build_from_row<T: Row>(row: &mut T) -> Result<Self, Box<Error>> {
                    if e!(row.next_is_null($Tuple)) {
                        Ok(None)
                    } else {
                        Ok(Some(($(try!($T::build_from_row(row))),+)))
                    }
                }
            }

            impl<$($T),+,$($ST),+> ValuesToSql<($($ST),+)> for ($($T),+) where
                $($T: ValuesToSql<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn values_to_sql(&self) -> Result<Vec<Option<Vec<u8>>>, Box<Error>> {
                    let values = e!(vec![$(try!(self.$idx.values_to_sql())),*]);
                    Ok(values.into_iter().flat_map(|v| v).collect())
                }
            }

            impl<$($T),+,$($ST),+> Queriable<($($ST),+)> for ($($T),+) where
                $($T: Queriable<$ST>),+,
                $($ST: NativeSqlType),+
            {
                type Row = ($($T::Row),+);

                fn build(row: Self::Row) -> Self {
                    ($($T::build(e!(row.$idx))),+)
                }
            }

            impl<$($T: Expression + NonAggregate),+> Expression for ($($T),+) {
                type SqlType = ($(<$T as Expression>::SqlType),+);

                fn to_sql(&self) -> String {
                    let parts: &[String] = e!(&[$(self.$idx.to_sql()),*]);
                    parts.join(", ")
                }
            }

            impl<$($T: Expression + NonAggregate),+> NonAggregate for ($($T),+) {
            }

            impl<$($T: Column<Table=T>),+, T: Table> InsertableColumns for ($($T),+) {
                type Table = T;
                type SqlType = ($(<$T as Column>::SqlType),+);

                fn names(&self) -> String {
                    let parts: &[String] = e!(&[$(self.$idx.name()),*]);
                    parts.join(", ")
                }
            }

            impl<$($T),+, $($ST),+, QS>
                SelectableExpression<QS, ($($ST),+)>
                for ($($T),+) where
                $($ST: NativeSqlType),+,
                $($T: SelectableExpression<QS, $ST> + NonAggregate),+,
                QS: QuerySource,
            {
            }

            impl<$($T),+, $($ST),+, QS>
                SelectableExpression<QS, Nullable<($($ST),+)>>
                for ($($T),+) where
                $($ST: NativeSqlType),+,
                $($T: SelectableExpression<QS, Nullable<$ST>> + NonAggregate),+,
                QS: QuerySource,
            {
            }

            impl<$($T),+, $($ST),+> AsBindParam<($($ST),+)> for ($($T),+) where
                $($T: AsBindParam<$ST>),+,
                $($ST: NativeSqlType),+,
            {
                fn as_bind_param(&self, idx: &mut usize) -> String {
                    e!([$(self.$idx.as_bind_param(idx)),+].join(","))
                }

                fn as_bind_param_for_insert(&self, idx: &mut usize) -> String {
                    e!([$(self.$idx.as_bind_param_for_insert(idx)),+].join(","))
                }
            }
        )+
    }
}

tuple_impls! {
    2 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
    }
    3 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
    }
    4 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
    }
    5 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
    }
    6 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
    }
    7 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
    }
    8 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
    }
    9 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
    }
    10 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
    }
    11 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
        (10) -> K, SK, TK,
    }
    12 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
        (10) -> K, SK, TK,
        (11) -> L, SL, TL,
    }
}
<commit_msg>Remove overly specific type constraint<commit_after>use expression::{Expression, SelectableExpression, NonAggregate};
use persistable::{AsBindParam, InsertableColumns};
use row::Row;
use std::error::Error;
use types::{NativeSqlType, FromSqlRow, ValuesToSql, Nullable};
use {Queriable, Table, Column, QuerySource};

// FIXME(https://github.com/rust-lang/rust/issues/19630) Remove this work-around
macro_rules! e {
    ($e:expr) => { $e }
}

macro_rules! tuple_impls {
    ($(
        $Tuple:tt {
            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
        }
    )+) => {
        $(
            impl<$($T:NativeSqlType),+> NativeSqlType for ($($T,)+) {}

            impl<$($T),+,$($ST),+> FromSqlRow<($($ST),+)> for ($($T),+) where
                $($T: FromSqlRow<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn build_from_row<T: Row>(row: &mut T) -> Result<Self, Box<Error>> {
                    Ok(($(try!($T::build_from_row(row))),+))
                }
            }

            impl<$($T),+,$($ST),+> FromSqlRow<Nullable<($($ST),+)>> for Option<($($T),+)> where
                $($T: FromSqlRow<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn build_from_row<T: Row>(row: &mut T) -> Result<Self, Box<Error>> {
                    if e!(row.next_is_null($Tuple)) {
                        Ok(None)
                    } else {
                        Ok(Some(($(try!($T::build_from_row(row))),+)))
                    }
                }
            }

            impl<$($T),+,$($ST),+> ValuesToSql<($($ST),+)> for ($($T),+) where
                $($T: ValuesToSql<$ST>),+,
                $($ST: NativeSqlType),+
            {
                fn values_to_sql(&self) -> Result<Vec<Option<Vec<u8>>>, Box<Error>> {
                    let values = e!(vec![$(try!(self.$idx.values_to_sql())),*]);
                    Ok(values.into_iter().flat_map(|v| v).collect())
                }
            }

            impl<$($T),+,$($ST),+> Queriable<($($ST),+)> for ($($T),+) where
                $($T: Queriable<$ST>),+,
                $($ST: NativeSqlType),+
            {
                type Row = ($($T::Row),+);

                fn build(row: Self::Row) -> Self {
                    ($($T::build(e!(row.$idx))),+)
                }
            }

            impl<$($T: Expression + NonAggregate),+> Expression for ($($T),+) {
                type SqlType = ($(<$T as Expression>::SqlType),+);

                fn to_sql(&self) -> String {
                    let parts: &[String] = e!(&[$(self.$idx.to_sql()),*]);
                    parts.join(", ")
                }
            }

            impl<$($T: Expression + NonAggregate),+> NonAggregate for ($($T),+) {
            }

            impl<$($T: Column<Table=T>),+, T: Table> InsertableColumns for ($($T),+) {
                type Table = T;
                type SqlType = ($(<$T as Column>::SqlType),+);

                fn names(&self) -> String {
                    let parts: &[String] = e!(&[$(self.$idx.name()),*]);
                    parts.join(", ")
                }
            }

            impl<$($T),+, $($ST),+, QS>
                SelectableExpression<QS, ($($ST),+)>
                for ($($T),+) where
                $($ST: NativeSqlType),+,
                $($T: SelectableExpression<QS, $ST>),+,
                ($($T),+): Expression,
                QS: QuerySource,
            {
            }

            impl<$($T),+, $($ST),+, QS>
                SelectableExpression<QS, Nullable<($($ST),+)>>
                for ($($T),+) where
                $($ST: NativeSqlType),+,
                $($T: SelectableExpression<QS, Nullable<$ST>>),+,
                ($($T),+): Expression,
                QS: QuerySource,
            {
            }

            impl<$($T),+, $($ST),+> AsBindParam<($($ST),+)> for ($($T),+) where
                $($T: AsBindParam<$ST>),+,
                $($ST: NativeSqlType),+,
            {
                fn as_bind_param(&self, idx: &mut usize) -> String {
                    e!([$(self.$idx.as_bind_param(idx)),+].join(","))
                }

                fn as_bind_param_for_insert(&self, idx: &mut usize) -> String {
                    e!([$(self.$idx.as_bind_param_for_insert(idx)),+].join(","))
                }
            }
        )+
    }
}

tuple_impls! {
    2 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
    }
    3 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
    }
    4 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
    }
    5 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
    }
    6 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
    }
    7 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
    }
    8 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
    }
    9 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
    }
    10 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
    }
    11 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
        (10) -> K, SK, TK,
    }
    12 {
        (0) -> A, SA, TA,
        (1) -> B, SB, TB,
        (2) -> C, SC, TC,
        (3) -> D, SD, TD,
        (4) -> E, SE, TE,
        (5) -> F, SF, TF,
        (6) -> G, SG, TG,
        (7) -> H, SH, TH,
        (8) -> I, SI, TI,
        (9) -> J, SJ, TJ,
        (10) -> K, SK, TK,
        (11) -> L, SL, TL,
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's

#[cfg(unix)]
extern crate libc;
extern crate walker;

#[macro_use]
extern crate uucore;

use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
use uucore::fs::display_permissions_unix;
#[cfg(not(windows))]
use uucore::mode;
use walker::Walker;

const NAME: &str = "chmod";
static SUMMARY: &str = "Change the mode of each FILE to MODE.
 With --reference, change the mode of each FILE to that of RFILE.";
static LONG_HELP: &str = "
 Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.
";

pub fn uumain(mut args: Vec<String>) -> i32 {
    let syntax = format!(
        "[OPTION]... MODE[,MODE]... FILE...
 {0} [OPTION]... OCTAL-MODE FILE...
 {0} [OPTION]... --reference=RFILE FILE...",
        NAME
    );
    let mut opts = app!(&syntax, SUMMARY, LONG_HELP);
    opts.optflag(
        "c",
        "changes",
        "like verbose but report only when a change is made",
    )
    // TODO: support --silent (can be done using clap)
    .optflag("f", "quiet", "suppress most error messages")
    .optflag(
        "v",
        "verbose",
        "output a diagnostic for every file processed",
    )
    .optflag(
        "",
        "no-preserve-root",
        "do not treat '/' specially (the default)",
    )
    .optflag("", "preserve-root", "fail to operate recursively on '/'")
    .optopt(
        "",
        "reference",
        "use RFILE's mode instead of MODE values",
        "RFILE",
    )
    .optflag("R", "recursive", "change files and directories recursively");

    // sanitize input for - at beginning (e.g. chmod -x testfile). Remove
    // the option and save it for later, after parsing is finished.
    let negative_option = sanitize_input(&mut args);

    let mut matches = opts.parse(args);
    if matches.free.is_empty() {
        show_error!("missing an argument");
        show_error!("for help, try '{} --help'", NAME);
        return 1;
    } else {
        let changes = matches.opt_present("changes");
        let quiet = matches.opt_present("quiet");
        let verbose = matches.opt_present("verbose");
        let preserve_root = matches.opt_present("preserve-root");
        let recursive = matches.opt_present("recursive");
        let fmode = matches
            .opt_str("reference")
            .and_then(|ref fref| match fs::metadata(fref) {
                Ok(meta) => Some(meta.mode()),
                Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
            });
        let cmode = if fmode.is_none() {
            // If there was a negative option, now it's a good time to
            // use it.
            if negative_option.is_some() {
                negative_option
            } else {
                Some(matches.free.remove(0))
            }
        } else {
            None
        };
        let chmoder = Chmoder {
            changes,
            quiet,
            verbose,
            preserve_root,
            recursive,
            fmode,
            cmode,
        };
        match chmoder.chmod(matches.free) {
            Ok(()) => {}
            Err(e) => return e,
        }
    }

    0
}

fn sanitize_input(args: &mut Vec<String>) -> Option<String> {
    for i in 0..args.len() {
        let first = args[i].chars().next().unwrap();
        if first != '-' {
            continue;
        }
        if let Some(second) = args[i].chars().nth(1) {
            match second {
                'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
                    return Some(args.remove(i));
                }
                _ => {}
            }
        }
    }
    None
}

struct Chmoder {
    changes: bool,
    quiet: bool,
    verbose: bool,
    preserve_root: bool,
    recursive: bool,
    fmode: Option<u32>,
    cmode: Option<String>,
}

impl Chmoder {
    fn chmod(&self, files: Vec<String>) -> Result<(), i32> {
        let mut r = Ok(());

        for filename in &files {
            let filename = &filename[..];
            let file = Path::new(filename);
            if file.exists() {
                if file.is_dir() {
                    if !self.preserve_root || filename != "/" {
                        if self.recursive {
                            let walk_dir = match Walker::new(&file) {
                                Ok(m) => m,
                                Err(f) => {
                                    crash!(1, "{}", f.to_string());
                                }
                            };
                            // XXX: here (and elsewhere) we see that this impl will have issues
                            // with non-UTF-8 filenames. Using OsString won't fix this because
                            // on Windows OsStrings cannot be built out of non-UTF-8 chars. One
                            // possible fix is to use CStrings rather than Strings in the args
                            // to chmod() and chmod_file().
                            r = self
                                .chmod(
                                    walk_dir
                                        .filter_map(|x| match x {
                                            Ok(o) => match o.path().into_os_string().to_str() {
                                                Some(s) => Some(s.to_owned()),
                                                None => None,
                                            },
                                            Err(_) => None,
                                        })
                                        .collect(),
                                )
                                .and(r);
                            r = self.chmod_file(&file, filename).and(r);
                        }
                    } else {
                        show_error!("could not change permissions of directory '{}'", filename);
                        r = Err(1);
                    }
                } else {
                    r = self.chmod_file(&file, filename).and(r);
                }
            } else {
                show_error!("no such file or directory '{}'", filename);
                r = Err(1);
            }
        }

        r
    }

    #[cfg(windows)]
    fn chmod_file(&self, file: &Path, name: &str) -> Result<(), i32> {
        // chmod is useless on Windows
        // it doesn't set any permissions at all
        // instead it just sets the readonly attribute on the file
        Err(0)
    }
    #[cfg(any(unix, target_os = "redox"))]
    fn chmod_file(&self, file: &Path, name: &str) -> Result<(), i32> {
        let mut fperm = match fs::metadata(name) {
            Ok(meta) => meta.mode() & 0o7777,
            Err(err) => {
                if !self.quiet {
                    show_error!("{}", err);
                }
                return Err(1);
            }
        };
        match self.fmode {
            Some(mode) => self.change_file(fperm, mode, file, name)?,
            None => {
                let cmode_unwrapped = self.cmode.clone().unwrap();
                for mode in cmode_unwrapped.split(',') {
                    // cmode is guaranteed to be Some in this case
                    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
                    let result = if mode.contains(arr) {
                        mode::parse_numeric(fperm, mode)
                    } else {
                        mode::parse_symbolic(fperm, mode, file.is_dir())
                    };
                    match result {
                        Ok(mode) => {
                            self.change_file(fperm, mode, file, name)?;
                            fperm = mode;
                        }
                        Err(f) => {
                            if !self.quiet {
                                show_error!("{}", f);
                            }
                            return Err(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }

    #[cfg(unix)]
    fn change_file(&self, fperm: u32, mode: u32, file: &Path, path: &str) -> Result<(), i32> {
        if fperm == mode {
            if self.verbose && !self.changes {
                show_info!(
                    "mode of '{}' retained as {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm)
                );
            }
            Ok(())
        } else if let Err(err) =
            fs::set_permissions(Path::new(path), fs::Permissions::from_mode(mode))
        {
            if !self.quiet {
                show_error!("{}", err);
            }
            if self.verbose {
                show_info!(
                    "failed to change mode of file '{}' from {:o} ({}) to {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm),
                    mode,
                    display_permissions_unix(mode)
                );
            }
            Err(1)
        } else {
            if self.verbose || self.changes {
                show_info!(
                    "mode of '{}' changed from {:o} ({}) to {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm),
                    mode,
                    display_permissions_unix(mode)
                );
            }
            Ok(())
        }
    }
}
<commit_msg>refactor help text and variable names<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's

#[cfg(unix)]
extern crate libc;
extern crate walker;

#[macro_use]
extern crate uucore;

use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
use uucore::fs::display_permissions_unix;
#[cfg(not(windows))]
use uucore::mode;
use walker::Walker;

const NAME: &str = "chmod";
static SUMMARY: &str = "Change the mode of each FILE to MODE.
 With --reference, change the mode of each FILE to that of RFILE.";
static LONG_HELP: &str = "
 Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.
";

pub fn uumain(mut args: Vec<String>) -> i32 {
    let syntax = format!(
        "[OPTION]... MODE[,MODE]... FILE...
 {0} [OPTION]... OCTAL-MODE FILE...
 {0} [OPTION]... --reference=RFILE FILE...",
        NAME
    );
    let mut opts = app!(&syntax, SUMMARY, LONG_HELP);
    opts.optflag(
        "c",
        "changes",
        "like verbose but report only when a change is made",
    )
    // TODO: support --silent (can be done using clap)
    .optflag("f", "quiet", "suppress most error messages")
    .optflag(
        "v",
        "verbose",
        "output a diagnostic for every file processed",
    )
    .optflag(
        "",
        "no-preserve-root",
        "do not treat '/' specially (the default)",
    )
    .optflag("", "preserve-root", "fail to operate recursively on '/'")
    .optopt(
        "",
        "reference",
        "use RFILE's mode instead of MODE values",
        "RFILE",
    )
    .optflag("R", "recursive", "change files and directories recursively");

    // sanitize input for - at beginning (e.g. chmod -x test_file). Remove
    // the option and save it for later, after parsing is finished.
    let negative_option = sanitize_input(&mut args);

    let mut matches = opts.parse(args);
    if matches.free.is_empty() {
        show_error!("missing an argument");
        show_error!("for help, try '{} --help'", NAME);
        return 1;
    } else {
        let changes = matches.opt_present("changes");
        let quiet = matches.opt_present("quiet");
        let verbose = matches.opt_present("verbose");
        let preserve_root = matches.opt_present("preserve-root");
        let recursive = matches.opt_present("recursive");
        let fmode = matches
            .opt_str("reference")
            .and_then(|ref fref| match fs::metadata(fref) {
                Ok(meta) => Some(meta.mode()),
                Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
            });
        let cmode = if fmode.is_none() {
            // If there was a negative option, now it's a good time to
            // use it.
            if negative_option.is_some() {
                negative_option
            } else {
                Some(matches.free.remove(0))
            }
        } else {
            None
        };
        let chmoder = Chmoder {
            changes,
            quiet,
            verbose,
            preserve_root,
            recursive,
            fmode,
            cmode,
        };
        match chmoder.chmod(matches.free) {
            Ok(()) => {}
            Err(e) => return e,
        }
    }

    0
}

fn sanitize_input(args: &mut Vec<String>) -> Option<String> {
    for i in 0..args.len() {
        let first = args[i].chars().next().unwrap();
        if first != '-' {
            continue;
        }
        if let Some(second) = args[i].chars().nth(1) {
            match second {
                'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
                    return Some(args.remove(i));
                }
                _ => {}
            }
        }
    }
    None
}

struct Chmoder {
    changes: bool,
    quiet: bool,
    verbose: bool,
    preserve_root: bool,
    recursive: bool,
    fmode: Option<u32>,
    cmode: Option<String>,
}

impl Chmoder {
    fn chmod(&self, files: Vec<String>) -> Result<(), i32> {
        let mut r = Ok(());

        for filename in &files {
            let filename = &filename[..];
            let file = Path::new(filename);
            if file.exists() {
                if file.is_dir() {
                    if !self.preserve_root || filename != "/" {
                        if self.recursive {
                            let walk_dir = match Walker::new(&file) {
                                Ok(m) => m,
                                Err(f) => {
                                    crash!(1, "{}", f.to_string());
                                }
                            };
                            // XXX: here (and elsewhere) we see that this impl will have issues
                            // with non-UTF-8 filenames. Using OsString won't fix this because
                            // on Windows OsStrings cannot be built out of non-UTF-8 chars. One
                            // possible fix is to use CStrings rather than Strings in the args
                            // to chmod() and chmod_file().
                            r = self
                                .chmod(
                                    walk_dir
                                        .filter_map(|x| match x {
                                            Ok(o) => match o.path().into_os_string().to_str() {
                                                Some(s) => Some(s.to_owned()),
                                                None => None,
                                            },
                                            Err(_) => None,
                                        })
                                        .collect(),
                                )
                                .and(r);
                            r = self.chmod_file(&file, filename).and(r);
                        }
                    } else {
                        show_error!("could not change permissions of directory '{}'", filename);
                        r = Err(1);
                    }
                } else {
                    r = self.chmod_file(&file, filename).and(r);
                }
            } else {
                show_error!("no such file or directory '{}'", filename);
                r = Err(1);
            }
        }

        r
    }

    #[cfg(windows)]
    fn chmod_file(&self, file: &Path, name: &str) -> Result<(), i32> {
        // chmod is useless on Windows
        // it doesn't set any permissions at all
        // instead it just sets the readonly attribute on the file
        Err(0)
    }
    #[cfg(any(unix, target_os = "redox"))]
    fn chmod_file(&self, file: &Path, name: &str) -> Result<(), i32> {
        let mut fperm = match fs::metadata(name) {
            Ok(meta) => meta.mode() & 0o7777,
            Err(err) => {
                if !self.quiet {
                    show_error!("{}", err);
                }
                return Err(1);
            }
        };
        match self.fmode {
            Some(mode) => self.change_file(fperm, mode, file, name)?,
            None => {
                let cmode_unwrapped = self.cmode.clone().unwrap();
                for mode in cmode_unwrapped.split(',') {
                    // cmode is guaranteed to be Some in this case
                    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
                    let result = if mode.contains(arr) {
                        mode::parse_numeric(fperm, mode)
                    } else {
                        mode::parse_symbolic(fperm, mode, file.is_dir())
                    };
                    match result {
                        Ok(mode) => {
                            self.change_file(fperm, mode, file, name)?;
                            fperm = mode;
                        }
                        Err(f) => {
                            if !self.quiet {
                                show_error!("{}", f);
                            }
                            return Err(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }

    #[cfg(unix)]
    fn change_file(&self, fperm: u32, mode: u32, file: &Path, path: &str) -> Result<(), i32> {
        if fperm == mode {
            if self.verbose && !self.changes {
                show_info!(
                    "mode of '{}' retained as {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm)
                );
            }
            Ok(())
        } else if let Err(err) =
            fs::set_permissions(Path::new(path), fs::Permissions::from_mode(mode))
        {
            if !self.quiet {
                show_error!("{}", err);
            }
            if self.verbose {
                show_info!(
                    "failed to change mode of file '{}' from {:o} ({}) to {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm),
                    mode,
                    display_permissions_unix(mode)
                );
            }
            Err(1)
        } else {
            if self.verbose || self.changes {
                show_info!(
                    "mode of '{}' changed from {:o} ({}) to {:o} ({})",
                    file.display(),
                    fperm,
                    display_permissions_unix(fperm),
                    mode,
                    display_permissions_unix(mode)
                );
            }
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Akira Hayakawa <ruby.wktk@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) PREFIXaa

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::char;
use std::fs::{File, OpenOptions};
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;

static NAME: &str = "split";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let mut opts = getopts::Options::new();

    opts.optopt(
        "a",
        "suffix-length",
        "use suffixes of length N (default 2)",
        "N",
    );
    opts.optopt("b", "bytes", "put SIZE bytes per output file", "SIZE");
    opts.optopt(
        "C",
        "line-bytes",
        "put at most SIZE bytes of lines per output file",
        "SIZE",
    );
    opts.optflag(
        "d",
        "numeric-suffixes",
        "use numeric suffixes instead of alphabetic",
    );
    opts.optopt(
        "",
        "additional-suffix",
        "additional suffix to append to output file names",
        "SUFFIX",
    );
    opts.optopt("l", "lines", "put NUMBER lines per output file", "NUMBER");
    opts.optflag(
        "",
        "verbose",
        "print a diagnostic just before each output file is opened",
    );
    opts.optflag("h", "help", "display help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("h") {
        let msg = format!(
            "{0} {1}

Usage:
  {0} [OPTION]... [INPUT [PREFIX]]

Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
-, read standard input.",
            NAME, VERSION
        );

        println!(
            "{}\nSIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.",
            opts.usage(&msg)
        );
        return 0;
    }

    if matches.opt_present("V") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut settings = Settings {
        prefix: "".to_owned(),
        numeric_suffix: false,
        suffix_length: 0,
        additional_suffix: "".to_owned(),
        input: "".to_owned(),
        strategy: "".to_owned(),
        strategy_param: "".to_owned(),
        verbose: false,
    };

    settings.numeric_suffix = matches.opt_present("d");

    settings.suffix_length = match matches.opt_str("a") {
        Some(n) => match n.parse() {
            Ok(m) => m,
            Err(e) => crash!(1, "cannot parse num: {}", e),
        },
        None => 2,
    };

    settings.additional_suffix = if matches.opt_present("additional-suffix") {
        matches.opt_str("additional-suffix").unwrap()
    } else {
        "".to_owned()
    };

    settings.verbose = matches.opt_present("verbose");

    settings.strategy = "l".to_owned();
    settings.strategy_param = "1000".to_owned();
    let strategies = vec!["b", "C", "l"];
    for e in &strategies {
        if let Some(a) = matches.opt_str(*e) {
            if settings.strategy == "l" {
                settings.strategy = (*e).to_owned();
                settings.strategy_param = a;
            } else {
                crash!(1, "{}: cannot split in more than one way", NAME)
            }
        }
    }

    let mut v = matches.free.iter();
    let (input, prefix) = match (v.next(), v.next()) {
        (Some(a), None) => (a.to_owned(), "x".to_owned()),
        (Some(a), Some(b)) => (a.clone(), b.clone()),
        (None, _) => ("-".to_owned(), "x".to_owned()),
    };
    settings.input = input;
    settings.prefix = prefix;

    split(&settings)
}

struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: usize,
    additional_suffix: String,
    input: String,
    strategy: String,
    strategy_param: String,
    verbose: bool,
}

struct SplitControl {
    current_line: String,   // Don't touch
    request_new_file: bool, // Splitter implementation requests new file
}

trait Splitter {
    // Consume the current_line and return the consumed string
    fn consume(&mut self, _: &mut SplitControl) -> String;
}

struct LineSplitter {
    saved_lines_to_write: usize,
    lines_to_write: usize,
}

impl LineSplitter {
    fn new(settings: &Settings) -> LineSplitter {
        let n = match settings.strategy_param.parse() {
            Ok(a) => a,
            Err(e) => crash!(1, "invalid number of lines: {}", e),
        };
        LineSplitter {
            saved_lines_to_write: n,
            lines_to_write: n,
        }
    }
}

impl Splitter for LineSplitter {
    fn consume(&mut self, control: &mut SplitControl) -> String {
        self.lines_to_write -= 1;
        if self.lines_to_write == 0 {
            self.lines_to_write = self.saved_lines_to_write;
            control.request_new_file = true;
        }
        control.current_line.clone()
    }
}

struct ByteSplitter {
    saved_bytes_to_write: usize,
    bytes_to_write: usize,
    break_on_line_end: bool,
    require_whole_line: bool,
}

impl ByteSplitter {
    fn new(settings: &Settings) -> ByteSplitter {
        let mut strategy_param: Vec<char> = settings.strategy_param.chars().collect();
        let suffix = strategy_param.pop().unwrap();
        let multiplier = match suffix {
            '0'..='9' => 1usize,
            'b' => 512usize,
            'k' => 1024usize,
            'm' => 1024usize * 1024usize,
            _ => crash!(1, "invalid number of bytes"),
        };
        let n = if suffix.is_alphabetic() {
            match strategy_param
                .iter()
                .cloned()
                .collect::<String>()
                .parse::<usize>()
            {
                Ok(a) => a,
                Err(e) => crash!(1, "invalid number of bytes: {}", e),
            }
        } else {
            match settings.strategy_param.parse::<usize>() {
                Ok(a) => a,
                Err(e) => crash!(1, "invalid number of bytes: {}", e),
            }
        };
        ByteSplitter {
            saved_bytes_to_write: n * multiplier,
            bytes_to_write: n * multiplier,
            break_on_line_end: settings.strategy == "b",
            require_whole_line: false,
        }
    }
}

impl Splitter for ByteSplitter {
    fn consume(&mut self, control: &mut SplitControl) -> String {
        let line = control.current_line.clone();
        let n = std::cmp::min(line.chars().count(), self.bytes_to_write);
        if self.require_whole_line && n < line.chars().count() {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
            self.require_whole_line = false;
            return "".to_owned();
        }
        self.bytes_to_write -= n;
        if n == 0 {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
        }
        if self.break_on_line_end && n == line.chars().count() {
            self.require_whole_line = self.break_on_line_end;
        }
        line[..n].to_owned()
    }
}

// (1, 3) -> "aab"
#[allow(clippy::many_single_char_names)]
fn str_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 26usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
#[allow(clippy::many_single_char_names)]
fn num_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 10usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r as u32, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> i32 {
    let mut reader = BufReader::new(if settings.input == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let r = match File::open(Path::new(&settings.input)) {
            Ok(a) => a,
            Err(_) => crash!(
                1,
                "cannot open '{}' for reading: No such file or directory",
                settings.input
            ),
        };
        Box::new(r) as Box<dyn Read>
    });

    let mut splitter: Box<dyn Splitter> = match settings.strategy.as_ref() {
        "l" => Box::new(LineSplitter::new(settings)),
        "b" | "C" => Box::new(ByteSplitter::new(settings)),
        a => crash!(1, "strategy {} not supported", a),
    };

    let mut control = SplitControl {
        current_line: "".to_owned(), // Request new line
        request_new_file: true,      // Request new file
    };

    let mut writer = BufWriter::new(Box::new(stdout()) as Box<dyn Write>);
    let mut fileno = 0;
    loop {
        if control.current_line.chars().count() == 0 {
            match reader.read_line(&mut control.current_line) {
                Ok(0) | Err(_) => break,
                _ => {}
            }
        }

        if control.request_new_file {
            let mut filename = settings.prefix.clone();
            filename.push_str(
                if settings.numeric_suffix {
                    num_prefix(fileno, settings.suffix_length)
                } else {
                    str_prefix(fileno, settings.suffix_length)
                }.as_ref(),
            );
            filename.push_str(
                settings.additional_suffix
                .as_ref()
            );

            if fileno != 0 {
                crash_if_err!(1, writer.flush());
            }
            fileno += 1;
            writer = BufWriter::new(Box::new(
                OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(Path::new(&filename))
                    .unwrap(),
            ) as Box<dyn Write>);
            control.request_new_file = false;
            if settings.verbose {
                println!("creating file '{}'", filename);
            }
        }

        let consumed = splitter.consume(&mut control);
        crash_if_err!(1, writer.write_all(consumed.as_bytes()));

        let advance = consumed.chars().count();
        let clone = control.current_line.clone();
        let sl = clone;
        control.current_line = sl[advance..sl.chars().count()].to_owned();
    }
    0
}
<commit_msg>Update src/uu/split/src/split.rs<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Akira Hayakawa <ruby.wktk@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) PREFIXaa

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::char;
use std::fs::{File, OpenOptions};
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;

static NAME: &str = "split";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let mut opts = getopts::Options::new();

    opts.optopt(
        "a",
        "suffix-length",
        "use suffixes of length N (default 2)",
        "N",
    );
    opts.optopt("b", "bytes", "put SIZE bytes per output file", "SIZE");
    opts.optopt(
        "C",
        "line-bytes",
        "put at most SIZE bytes of lines per output file",
        "SIZE",
    );
    opts.optflag(
        "d",
        "numeric-suffixes",
        "use numeric suffixes instead of alphabetic",
    );
    opts.optopt(
        "",
        "additional-suffix",
        "additional suffix to append to output file names",
        "SUFFIX",
    );
    opts.optopt("l", "lines", "put NUMBER lines per output file", "NUMBER");
    opts.optflag(
        "",
        "verbose",
        "print a diagnostic just before each output file is opened",
    );
    opts.optflag("h", "help", "display help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    if matches.opt_present("h") {
        let msg = format!(
            "{0} {1}

Usage:
  {0} [OPTION]... [INPUT [PREFIX]]

Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
-, read standard input.",
            NAME, VERSION
        );

        println!(
            "{}\nSIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.",
            opts.usage(&msg)
        );
        return 0;
    }

    if matches.opt_present("V") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut settings = Settings {
        prefix: "".to_owned(),
        numeric_suffix: false,
        suffix_length: 0,
        additional_suffix: "".to_owned(),
        input: "".to_owned(),
        strategy: "".to_owned(),
        strategy_param: "".to_owned(),
        verbose: false,
    };

    settings.numeric_suffix = matches.opt_present("d");

    settings.suffix_length = match matches.opt_str("a") {
        Some(n) => match n.parse() {
            Ok(m) => m,
            Err(e) => crash!(1, "cannot parse num: {}", e),
        },
        None => 2,
    };

    settings.additional_suffix = if matches.opt_present("additional-suffix") {
        matches.opt_str("additional-suffix").unwrap()
    } else {
        "".to_owned()
    };

    settings.verbose = matches.opt_present("verbose");

    settings.strategy = "l".to_owned();
    settings.strategy_param = "1000".to_owned();
    let strategies = vec!["b", "C", "l"];
    for e in &strategies {
        if let Some(a) = matches.opt_str(*e) {
            if settings.strategy == "l" {
                settings.strategy = (*e).to_owned();
                settings.strategy_param = a;
            } else {
                crash!(1, "{}: cannot split in more than one way", NAME)
            }
        }
    }

    let mut v = matches.free.iter();
    let (input, prefix) = match (v.next(), v.next()) {
        (Some(a), None) => (a.to_owned(), "x".to_owned()),
        (Some(a), Some(b)) => (a.clone(), b.clone()),
        (None, _) => ("-".to_owned(), "x".to_owned()),
    };
    settings.input = input;
    settings.prefix = prefix;

    split(&settings)
}

struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: usize,
    additional_suffix: String,
    input: String,
    strategy: String,
    strategy_param: String,
    verbose: bool,
}

struct SplitControl {
    current_line: String,   // Don't touch
    request_new_file: bool, // Splitter implementation requests new file
}

trait Splitter {
    // Consume the current_line and return the consumed string
    fn consume(&mut self, _: &mut SplitControl) -> String;
}

struct LineSplitter {
    saved_lines_to_write: usize,
    lines_to_write: usize,
}

impl LineSplitter {
    fn new(settings: &Settings) -> LineSplitter {
        let n = match settings.strategy_param.parse() {
            Ok(a) => a,
            Err(e) => crash!(1, "invalid number of lines: {}", e),
        };
        LineSplitter {
            saved_lines_to_write: n,
            lines_to_write: n,
        }
    }
}

impl Splitter for LineSplitter {
    fn consume(&mut self, control: &mut SplitControl) -> String {
        self.lines_to_write -= 1;
        if self.lines_to_write == 0 {
            self.lines_to_write = self.saved_lines_to_write;
            control.request_new_file = true;
        }
        control.current_line.clone()
    }
}

struct ByteSplitter {
    saved_bytes_to_write: usize,
    bytes_to_write: usize,
    break_on_line_end: bool,
    require_whole_line: bool,
}

impl ByteSplitter {
    fn new(settings: &Settings) -> ByteSplitter {
        let mut strategy_param: Vec<char> = settings.strategy_param.chars().collect();
        let suffix = strategy_param.pop().unwrap();
        let multiplier = match suffix {
            '0'..='9' => 1usize,
            'b' => 512usize,
            'k' => 1024usize,
            'm' => 1024usize * 1024usize,
            _ => crash!(1, "invalid number of bytes"),
        };
        let n = if suffix.is_alphabetic() {
            match strategy_param
                .iter()
                .cloned()
                .collect::<String>()
                .parse::<usize>()
            {
                Ok(a) => a,
                Err(e) => crash!(1, "invalid number of bytes: {}", e),
            }
        } else {
            match settings.strategy_param.parse::<usize>() {
                Ok(a) => a,
                Err(e) => crash!(1, "invalid number of bytes: {}", e),
            }
        };
        ByteSplitter {
            saved_bytes_to_write: n * multiplier,
            bytes_to_write: n * multiplier,
            break_on_line_end: settings.strategy == "b",
            require_whole_line: false,
        }
    }
}

impl Splitter for ByteSplitter {
    fn consume(&mut self, control: &mut SplitControl) -> String {
        let line = control.current_line.clone();
        let n = std::cmp::min(line.chars().count(), self.bytes_to_write);
        if self.require_whole_line && n < line.chars().count() {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
            self.require_whole_line = false;
            return "".to_owned();
        }
        self.bytes_to_write -= n;
        if n == 0 {
            self.bytes_to_write = self.saved_bytes_to_write;
            control.request_new_file = true;
        }
        if self.break_on_line_end && n == line.chars().count() {
            self.require_whole_line = self.break_on_line_end;
        }
        line[..n].to_owned()
    }
}

// (1, 3) -> "aab"
#[allow(clippy::many_single_char_names)]
fn str_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 26usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
#[allow(clippy::many_single_char_names)]
fn num_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 10usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r as u32, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> i32 {
    let mut reader = BufReader::new(if settings.input == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let r = match File::open(Path::new(&settings.input)) {
            Ok(a) => a,
            Err(_) => crash!(
                1,
                "cannot open '{}' for reading: No such file or directory",
                settings.input
            ),
        };
        Box::new(r) as Box<dyn Read>
    });

    let mut splitter: Box<dyn Splitter> = match settings.strategy.as_ref() {
        "l" => Box::new(LineSplitter::new(settings)),
        "b" | "C" => Box::new(ByteSplitter::new(settings)),
        a => crash!(1, "strategy {} not supported", a),
    };

    let mut control = SplitControl {
        current_line: "".to_owned(), // Request new line
        request_new_file: true,      // Request new file
    };

    let mut writer = BufWriter::new(Box::new(stdout()) as Box<dyn Write>);
    let mut fileno = 0;
    loop {
        if control.current_line.chars().count() == 0 {
            match reader.read_line(&mut control.current_line) {
                Ok(0) | Err(_) => break,
                _ => {}
            }
        }

        if control.request_new_file {
            let mut filename = settings.prefix.clone();
            filename.push_str(
                if settings.numeric_suffix {
                    num_prefix(fileno, settings.suffix_length)
                } else {
                    str_prefix(fileno, settings.suffix_length)
                }.as_ref(),
            );
            filename.push_str(
                settings.additional_suffix
                .as_ref()
            );

            if fileno != 0 {
                crash_if_err!(1, writer.flush());
            }
            fileno += 1;
            writer = BufWriter::new(Box::new(
                OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(Path::new(&filename))
                    .unwrap(),
            ) as Box<dyn Write>);
            control.request_new_file = false;
            if settings.verbose {
                println!("creating file '{}'", filename);
            }
        }

        let consumed = splitter.consume(&mut control);
        crash_if_err!(1, writer.write_all(consumed.as_bytes()));

        let advance = consumed.chars().count();
        let clone = control.current_line.clone();
        let sl = clone;
        control.current_line = sl[advance..sl.chars().count()].to_owned();
    }
    0
}
<|endoftext|>


<commit_before>use kay::{Recipient, Actor, Fate};
use ::core::geometry::AnyShape;
use super::CurrentPlan;

#[derive(Default)]
pub struct Deselecter;
impl Actor for Deselecter {}

use super::InitInteractable;
use core::ui::Add;

impl Recipient<InitInteractable> for Deselecter {
    fn receive(&mut self, _msg: &InitInteractable) -> Fate {
        println!("adding deselecter");
        ::core::ui::UserInterface::id() << Add::Interactable3d(Self::id(), AnyShape::Everywhere, 2);
        Fate::Live
    }
}

use super::ClearInteractable;
use core::ui::Remove;

impl Recipient<ClearInteractable> for Deselecter {
    fn receive(&mut self, _msg: &ClearInteractable) -> Fate {
        println!("removing deselecter");
        ::core::ui::UserInterface::id() << Remove::Interactable3d(Self::id());
        Fate::Die
    }
}

use core::ui::Event3d;
use super::{ChangeIntent, Intent, IntentProgress};

impl Recipient<Event3d> for Deselecter {
    fn receive(&mut self, msg: &Event3d) -> Fate {
        match *msg {
            Event3d::DragFinished { .. } => {
                CurrentPlan::id() << ChangeIntent(Intent::Deselect, IntentProgress::Immediate);
                Fate::Live
            }
            _ => Fate::Live,
        }
    }
}

pub fn setup() {
    Deselecter::register_default();
    Deselecter::handle::<InitInteractable>();
    Deselecter::handle::<ClearInteractable>();
    Deselecter::handle::<Event3d>();
}
<commit_msg>remove println<commit_after>use kay::{Recipient, Actor, Fate};
use ::core::geometry::AnyShape;
use super::CurrentPlan;

#[derive(Default)]
pub struct Deselecter;
impl Actor for Deselecter {}

use super::InitInteractable;
use core::ui::Add;

impl Recipient<InitInteractable> for Deselecter {
    fn receive(&mut self, _msg: &InitInteractable) -> Fate {
        println!("adding deselecter");
        ::core::ui::UserInterface::id() << Add::Interactable3d(Self::id(), AnyShape::Everywhere, 2);
        Fate::Live
    }
}

use super::ClearInteractable;
use core::ui::Remove;

impl Recipient<ClearInteractable> for Deselecter {
    fn receive(&mut self, _msg: &ClearInteractable) -> Fate {
        ::core::ui::UserInterface::id() << Remove::Interactable3d(Self::id());
        Fate::Die
    }
}

use core::ui::Event3d;
use super::{ChangeIntent, Intent, IntentProgress};

impl Recipient<Event3d> for Deselecter {
    fn receive(&mut self, msg: &Event3d) -> Fate {
        match *msg {
            Event3d::DragFinished { .. } => {
                CurrentPlan::id() << ChangeIntent(Intent::Deselect, IntentProgress::Immediate);
                Fate::Live
            }
            _ => Fate::Live,
        }
    }
}

pub fn setup() {
    Deselecter::register_default();
    Deselecter::handle::<InitInteractable>();
    Deselecter::handle::<ClearInteractable>();
    Deselecter::handle::<Event3d>();
}
<|endoftext|>


<commit_before>extern crate alignments;

use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;
use std::collections::{BTreeMap, BTreeSet};
use alignments::{align_seqs, align_seqs_seq, align_alignments};

#[derive(Debug)]
struct Matrix {
    elems: BTreeMap<usize, BTreeMap<usize, f64>>,
    keys: BTreeSet<usize>,
}

impl Matrix {
    fn new() -> Matrix {
        Matrix {
            elems: BTreeMap::new(),
            keys: BTreeSet::new(),
        }
    }

    fn insert(&mut self, c1: &usize, c2: &usize, val: f64) {
        let mut ins_map = self.elems.entry(*c1).or_insert_with(BTreeMap::new);
        ins_map.insert(*c2, val);
        self.keys.insert(*c1);
        self.keys.insert(*c2);
    }

    fn len(&self) -> usize {
        self.keys.len()
    }

    fn get_d(&self, c1: &usize, c2: &usize) -> &f64 {
        match self.elems.get(c1) {
            Some(map) => {
                match map.get(c2) {
                    Some(val) => val,
                    None => &self.elems[c2][c1],
                }
            }
            None => {
                match self.elems.get(c2) {
                    Some(map) => {
                        match map.get(c1) {
                            Some(val) => val,
                            None => panic!("c1 wasn't found"),
                        }
                    }
                    None => panic!("c2 wasn't found"),
                }
            }
        }
    }

    fn s_calculation(&self, c: &usize) -> f64 {
        let mut keys = self.keys.clone();
        if keys.remove(c) {
            let mut sum = 0.0;
            for &key in &keys {
                match self.elems.get(c) {
                    Some(map) => {
                        match map.get(&key) {
                            Some(val) => sum += *val,
                            None => sum += self.elems[&key][c],
                        }
                    }
                    None => sum += self.elems[&key][c],
                }
            }
            sum / (keys.len() - 1) as f64
        } else {
            panic!("Key not found in matrix");
        }
    }

    fn m_calculation(&self, c1: &usize, c2: &usize) -> f64 {
        *self.get_d(c1, c2) as f64 - self.s_calculation(c1) - self.s_calculation(c2)
    }

    fn lowest_m(&self) -> (f64, usize, usize) {
        let mut iter = self.keys.iter();
        let mut key_1 = match iter.next() {
            Some(val) => val,
            None => panic!("No elements in matrix"),
        };

        let mut lowest = (999.9, *key_1, *key_1);

        for key_2 in iter {
            let m = self.m_calculation(key_1, key_2);
            println!("M_{:X}.{:X} = {}", key_1, key_2, m);

            if lowest.0 > m {
                lowest = (m, *key_1, *key_2);
            }
            key_1 = key_2;
        }

        lowest
    }

    fn join(&mut self, k1: &usize, k2: &usize, k: &usize) -> Matrix {
        if !(self.keys.contains(k1) || self.keys.contains(k2)) {
            panic!("Keys aren't in matrix");
        }
        /********************************************************************/
        let d_12_2 = *self.get_d(k1, k2) as f64 / 2.0;
        let s_1 = self.s_calculation(k1);
        let s_2 = self.s_calculation(k2);
        println!("S_{:X}.{:X} = {}", k1, k, d_12_2 + (s_1 - s_2) / 2.0);
        println!("S_{:X}.{:X} = {}", k2, k, d_12_2 + (s_2 - s_1) / 2.0);
        /********************************************************************/
        let mut elems = self.elems.clone();
        elems.remove(k1);
        elems.remove(k2);
        for val in elems.values_mut() {
            val.remove(k1);
            val.remove(k2);
        }

        let mut keys = self.keys.clone();
        keys.remove(k1);
        keys.remove(k2);
        let rem_keys = keys.clone();

        let mut ret_m = Matrix {
            elems: elems,
            keys: keys,
        };

        for key in rem_keys {
            let val = self.get_d(k1, &key) + self.get_d(k2, &key) - self.get_d(k1, k2);
            ret_m.insert(k, &key, val / 2.0);
        }

        ret_m
    }

    fn print_matrix(&self) {
        for (key, val) in &self.elems {
            println!("{:X}: {:?}", key, val);
        }
    }

    fn print_s_calculations(&self) {
        for &key in &self.keys {
            println!("S_{:X} = {}", key, self.s_calculation(&key));
        }
    }

    fn keys(&self) -> Vec<usize> {
        self.keys.iter().cloned().collect()
    }
}

#[derive(Debug)]
struct GuideTree {
    aligns: BTreeMap<usize, Vec<String>>,
}

impl GuideTree {
    fn new() -> GuideTree {
        GuideTree { aligns: BTreeMap::new() }
    }

    fn insert(&mut self, key: &usize, align: String) {
        self.aligns.insert(*key, vec![align]);
    }

    fn join(&mut self, k1: &usize, k2: &usize, kj: &usize) {
        let join_align: Vec<String>;
        {
            let aligns_1 = &self.aligns[k1];
            let aligns_2 = &self.aligns[k2];

            join_align = if aligns_1.len() == 1 {
                if aligns_2.len() == 1 {
                    align_seqs(aligns_1[0].clone(), aligns_2[0].clone())
                } else {
                    align_seqs_seq(aligns_2.clone(), aligns_1[0].clone())
                }
            } else if aligns_2.len() == 1 {
                if aligns_1.len() == 1 {
                    align_seqs(aligns_1[0].clone(), aligns_2[0].clone())
                } else {
                    align_seqs_seq(aligns_1.clone(), aligns_2[0].clone())
                }
            } else {
                align_alignments(aligns_1.clone(), aligns_2.clone())
            };
        }

        self.aligns.insert(*kj, join_align);
    }
}

fn distance_score(align_1: &str, align_2: &str) -> f64 {
    let mut x_count = 0.0;
    let mut y_count = 0.0;
    let len = align_1.len();

    for i in 0..len {
        let c1 = align_1.chars().nth(i).unwrap();
        let c2 = align_2.chars().nth(i).unwrap();

        if c1 != '_' && c2 != '_' {
            // non-gap positions
            x_count += 1.0;
            if c1 == c2 {
                // identical positions
                y_count += 1.0;
            }
        }
    }

    // println!("x: {}, y: {}", x_count, y_count);

    1.0 - (y_count / x_count)
}

fn get_sequences(path: &str) -> Vec<String> {
    let mut ret_vec = Vec::new();
    let f = File::open(path).expect("Couldn't open file");
    let f = BufReader::new(f);
    for line in f.lines() {
        ret_vec.push(line.unwrap());
    }

    ret_vec
}

fn mult_seq_alignment(input: &[String]) {
    let mut matrix = Matrix::new();
    /****************************************************/
    for (i, seq_1) in input.iter().enumerate() {
        let mut j = i;
        for seq_2 in input.iter().skip(i + 1) {
            j += 1;
            if i != j {
                let aligns = align_seqs(seq_1.clone(), seq_2.clone());
                matrix.insert(&i, &j, distance_score(&aligns[0], &aligns[1]));
                println!("{}-{} > {:#?} - {}",
                         i,
                         j,
                         aligns,
                         distance_score(&aligns[0], &aligns[1]));
            }
        }
    }
    /******************** Guide Tree ********************/
    let mut g_tree = GuideTree::new();

    for (i, seq) in input.iter().enumerate() {
        g_tree.insert(&i, seq.clone());
    }
    /***************** Neighbor joining *****************/
    let mut letter = 193; // C1

    while matrix.len() - 2 > 0 {
        println!("");
        matrix.print_matrix();
        println!("");
        matrix.print_s_calculations();
        println!("");
        let (_, key_1, key_2) = matrix.lowest_m();
        println!("\nJoining: [{:X} and {:X}] -> {:X}", key_1, key_2, letter);
        matrix = matrix.join(&key_1, &key_2, &letter);
        g_tree.join(&key_1, &key_2, &letter);
        letter += 1;
    }
    matrix.print_matrix();
    let final_keys = matrix.keys();
    g_tree.join(&final_keys[0], &final_keys[1], &letter);
    println!("{:#?}", g_tree);
    /****************************************************/

    println!("Hello, world!");
}

fn main() {
    let input = get_sequences("input/MSA_16507.txt");
    // let input = get_sequences("input/test.txt");
    mult_seq_alignment(&input);
}
<commit_msg>File writing<commit_after>extern crate alignments;

use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;
use std::collections::{BTreeMap, BTreeSet};
use alignments::{align_seqs, align_seqs_seq, align_alignments};

#[derive(Debug)]
struct Matrix {
    elems: BTreeMap<usize, BTreeMap<usize, f64>>,
    keys: BTreeSet<usize>,
}

impl Matrix {
    fn new() -> Matrix {
        Matrix {
            elems: BTreeMap::new(),
            keys: BTreeSet::new(),
        }
    }

    fn insert(&mut self, c1: &usize, c2: &usize, val: f64) {
        let mut ins_map = self.elems.entry(*c1).or_insert_with(BTreeMap::new);
        ins_map.insert(*c2, val);
        self.keys.insert(*c1);
        self.keys.insert(*c2);
    }

    fn len(&self) -> usize {
        self.keys.len()
    }

    fn get_d(&self, c1: &usize, c2: &usize) -> &f64 {
        match self.elems.get(c1) {
            Some(map) => {
                match map.get(c2) {
                    Some(val) => val,
                    None => &self.elems[c2][c1],
                }
            }
            None => {
                match self.elems.get(c2) {
                    Some(map) => {
                        match map.get(c1) {
                            Some(val) => val,
                            None => panic!("c1 wasn't found"),
                        }
                    }
                    None => panic!("c2 wasn't found"),
                }
            }
        }
    }

    fn s_calculation(&self, c: &usize) -> f64 {
        let mut keys = self.keys.clone();
        if keys.remove(c) {
            let mut sum = 0.0;
            for &key in &keys {
                match self.elems.get(c) {
                    Some(map) => {
                        match map.get(&key) {
                            Some(val) => sum += *val,
                            None => sum += self.elems[&key][c],
                        }
                    }
                    None => sum += self.elems[&key][c],
                }
            }
            sum / (keys.len() - 1) as f64
        } else {
            panic!("Key not found in matrix");
        }
    }

    fn m_calculation(&self, c1: &usize, c2: &usize) -> f64 {
        *self.get_d(c1, c2) as f64 - self.s_calculation(c1) - self.s_calculation(c2)
    }

    fn lowest_m(&self) -> (f64, usize, usize) {
        let mut iter = self.keys.iter();
        let mut key_1 = match iter.next() {
            Some(val) => val,
            None => panic!("No elements in matrix"),
        };

        let mut lowest = (999.9, *key_1, *key_1);

        for key_2 in iter {
            let m = self.m_calculation(key_1, key_2);
            println!("M_{:X}.{:X} = {}", key_1, key_2, m);

            if lowest.0 > m {
                lowest = (m, *key_1, *key_2);
            }
            key_1 = key_2;
        }

        lowest
    }

    fn join(&mut self, k1: &usize, k2: &usize, k: &usize) -> Matrix {
        if !(self.keys.contains(k1) || self.keys.contains(k2)) {
            panic!("Keys aren't in matrix");
        }
        /********************************************************************/
        let d_12_2 = *self.get_d(k1, k2) as f64 / 2.0;
        let s_1 = self.s_calculation(k1);
        let s_2 = self.s_calculation(k2);
        println!("S_{:X}.{:X} = {}", k1, k, d_12_2 + (s_1 - s_2) / 2.0);
        println!("S_{:X}.{:X} = {}", k2, k, d_12_2 + (s_2 - s_1) / 2.0);
        /********************************************************************/
        let mut elems = self.elems.clone();
        elems.remove(k1);
        elems.remove(k2);
        for val in elems.values_mut() {
            val.remove(k1);
            val.remove(k2);
        }

        let mut keys = self.keys.clone();
        keys.remove(k1);
        keys.remove(k2);
        let rem_keys = keys.clone();

        let mut ret_m = Matrix {
            elems: elems,
            keys: keys,
        };

        for key in rem_keys {
            let val = self.get_d(k1, &key) + self.get_d(k2, &key) - self.get_d(k1, k2);
            ret_m.insert(k, &key, val / 2.0);
        }

        ret_m
    }

    fn print_matrix(&self) {
        for (key, val) in &self.elems {
            println!("{:X}: {:?}", key, val);
        }
    }

    fn print_s_calculations(&self) {
        for &key in &self.keys {
            println!("S_{:X} = {}", key, self.s_calculation(&key));
        }
    }

    fn keys(&self) -> Vec<usize> {
        self.keys.iter().cloned().collect()
    }
}

#[derive(Debug)]
struct GuideTree {
    aligns: BTreeMap<usize, Vec<String>>,
}

impl GuideTree {
    fn new() -> GuideTree {
        GuideTree { aligns: BTreeMap::new() }
    }

    fn insert(&mut self, key: &usize, align: String) {
        self.aligns.insert(*key, vec![align]);
    }

    fn join(&mut self, k1: &usize, k2: &usize, kj: &usize) {
        let join_align: Vec<String>;
        {
            let aligns_1 = &self.aligns[k1];
            let aligns_2 = &self.aligns[k2];

            join_align = if aligns_1.len() == 1 {
                if aligns_2.len() == 1 {
                    align_seqs(aligns_1[0].clone(), aligns_2[0].clone())
                } else {
                    align_seqs_seq(aligns_2.clone(), aligns_1[0].clone())
                }
            } else if aligns_2.len() == 1 {
                if aligns_1.len() == 1 {
                    align_seqs(aligns_1[0].clone(), aligns_2[0].clone())
                } else {
                    align_seqs_seq(aligns_1.clone(), aligns_2[0].clone())
                }
            } else {
                align_alignments(aligns_1.clone(), aligns_2.clone())
            };
        }

        self.aligns.insert(*kj, join_align);
    }

    fn alignments(&self, k: &usize) -> &Vec<String> {
        &self.aligns[k]
    }
}

fn distance_score(align_1: &str, align_2: &str) -> f64 {
    let mut x_count = 0.0;
    let mut y_count = 0.0;
    let len = align_1.len();

    for i in 0..len {
        let c1 = align_1.chars().nth(i).unwrap();
        let c2 = align_2.chars().nth(i).unwrap();

        if c1 != '_' && c2 != '_' {
            // non-gap positions
            x_count += 1.0;
            if c1 == c2 {
                // identical positions
                y_count += 1.0;
            }
        }
    }

    // println!("x: {}, y: {}", x_count, y_count);

    1.0 - (y_count / x_count)
}

fn get_sequences(path: &str) -> Vec<String> {
    let mut ret_vec = Vec::new();
    let f = File::open(path).expect("Couldn't open file");
    let f = BufReader::new(f);
    for line in f.lines() {
        ret_vec.push(line.unwrap());
    }

    ret_vec
}

fn mult_seq_alignment(input: &[String]) {
    let mut matrix = Matrix::new();
    /****************************************************/
    for (i, seq_1) in input.iter().enumerate() {
        let mut j = i;
        for seq_2 in input.iter().skip(i + 1) {
            j += 1;
            if i != j {
                let aligns = align_seqs(seq_1.clone(), seq_2.clone());
                matrix.insert(&i, &j, distance_score(&aligns[0], &aligns[1]));
                println!("{}-{} > {:#?} - {}",
                         i,
                         j,
                         aligns,
                         distance_score(&aligns[0], &aligns[1]));
            }
        }
    }
    /******************** Guide Tree ********************/
    let mut g_tree = GuideTree::new();

    for (i, seq) in input.iter().enumerate() {
        g_tree.insert(&i, seq.clone());
    }
    /***************** Neighbor joining *****************/
    let mut letter = 193; // C1

    while matrix.len() - 2 > 0 {
        println!("");
        matrix.print_matrix();
        println!("");
        matrix.print_s_calculations();
        println!("");
        let (_, key_1, key_2) = matrix.lowest_m();
        println!("\nJoining: [{:X} and {:X}] -> {:X}", key_1, key_2, letter);
        matrix = matrix.join(&key_1, &key_2, &letter);
        g_tree.join(&key_1, &key_2, &letter);
        letter += 1;
    }
    matrix.print_matrix();
    let final_keys = matrix.keys();
    g_tree.join(&final_keys[0], &final_keys[1], &letter);
    println!("{:#?}", g_tree);
    /****************************************************/
    let mut file = File::create("EPuma_Final_Alignments.txt").expect("Couldn't open write file");
    for align in g_tree.alignments(&letter) {
        write!(file, "{}\n", align).expect("Couldn't write in file");
    }
    /****************************************************/
    println!("Hello, world!");
}

fn main() {
    let input = get_sequences("input/MSA_16507.txt");
    // let input = get_sequences("input/test.txt");
    mult_seq_alignment(&input);
}
<|endoftext|>


<commit_before>/// Escape characters in a string that is to be inserted in Markdown
///
/// This only escapes characters that may be present in inline Markdown
/// to avoid string in curly attributes etc from being parsed as
/// emphasis, strong etc. The list of escaped characters may
/// need to be augmented in the future.
///
/// Previously we also escaped '[' but that is often used in JSON
/// values for enum and array parameters so is now not escaped.
pub(crate) fn escape(string: &str) -> String {
    string
        .replace('_', "\\_")
        .replace('*', "\\*")
        .replace('$', "\\$")
}

/// Unescape characters
///
/// See [`escape`] for which characters need to be unescaped.
pub(crate) fn unescape(string: &str) -> String {
    string
        .replace("\\_", "_")
        .replace("\\*", "*")
        .replace("\\$", "$")
}
<commit_msg>chore(Markdown codec): Allow dead code for now<commit_after>/// Escape characters in a string that is to be inserted in Markdown
///
/// This only escapes characters that may be present in inline Markdown
/// to avoid string in curly attributes etc from being parsed as
/// emphasis, strong etc. The list of escaped characters may
/// need to be augmented in the future.
///
/// Previously we also escaped '[' but that is often used in JSON
/// values for enum and array parameters so is now not escaped.
pub(crate) fn escape(string: &str) -> String {
    string
        .replace('_', "\\_")
        .replace('*', "\\*")
        .replace('$', "\\$")
}

/// Unescape characters
///
/// See [`escape`] for which characters need to be unescaped.
#[allow(dead_code)]
pub(crate) fn unescape(string: &str) -> String {
    string
        .replace("\\_", "_")
        .replace("\\*", "*")
        .replace("\\$", "$")
}
<|endoftext|>