<commit_before>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, Vec<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    // Add a clause, return the ID of the inserted clause
    fn add_clause(&mut self, clause : Vec<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id : i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>,
}

impl PartialAssignment {
    pub fn new(n : usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect(),
        }
    }

    pub fn assign(&mut self, v : usize, assn : bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
    }

    pub fn unassign(&mut self, v : usize) {
        self.assignment[v] = None;
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: Vec<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    use super::parse_dimacs_file;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }
}
<commit_msg>Implement propagate and unit_propagate<commit_after>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, Vec<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    /// Add a clause, return the ID of the inserted clause
    fn add_clause(&mut self, clause: Vec<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id: i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    /// Unit propagation: propagate the literal associated with the clause id `clause`, and remove
    /// it from `self.units`.
    fn unit_propagate(&mut self, unit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        let occurrences = &self.occurrences.remove(
            &self.clauses.get(&unit).expect("unit clause not found")[0]
        ).unwrap();
        for occ in occurrences {
            self.clauses.remove(&occ);
        }
        // This needs to be true, i.e. unit clause id needs to be in the unit clauses
        assert!(self.units.remove(&unit))
    }

    /// Remove all clauses containing literal `lit` from the CNF, and remove the negation of `lit`
    /// from the remaining clauses.
    fn propagate(&mut self, lit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        for occ in &self.occurrences.remove(&lit).unwrap() {
            self.clauses.remove(occ);
        }
    }
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>,
}

impl PartialAssignment {
    pub fn new(n : usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect(),
        }
    }

    pub fn assign(&mut self, v : usize, assn : bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
    }

    pub fn unassign(&mut self, v : usize) {
        self.assignment[v] = None;
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: Vec<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    use super::parse_dimacs_file;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }

    // TODO: Make this doc test (with unit propagate); create_tempfile may need to be an importable
    // macro up there
    #[test]
    fn propagate_works() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        println!("{:?}", cnf);
        cnf.propagate(2);
        println!("{:?}", cnf);
    }
}
<|endoftext|>


<commit_before>
use error::MpdResult;
use connection::{FromConn, MpdConnection, mpd_connection};
use songs::{MpdSong, mpd_song};
use libc;

extern {
    fn mpd_run_get_queue_song_pos(connection: *mut mpd_connection, pos: libc::c_uint) -> *mut mpd_song;
    fn mpd_run_move_id(connection: *mut mpd_connection, from: libc::c_uint, to: libc::c_uint) -> bool;
    fn mpd_run_swap_id(connection: *mut mpd_connection, id1: libc::c_uint, id2: libc::c_uint) -> bool;
    fn mpd_run_swap(connection: *mut mpd_connection, pos1: libc::c_uint, pos2: libc::c_uint) -> bool;
}

pub struct MpdQueue<'a> {
    conn: &'a MpdConnection
}

impl<'a> MpdQueue<'a> {
    pub fn from_conn(conn: &'a MpdConnection) -> MpdQueue<'a> {
        MpdQueue { conn: conn }
    }

    pub fn get(&self, index: uint) -> Option<MpdSong> {
        let song = unsafe { mpd_run_get_queue_song_pos(self.conn.conn, index as libc::c_uint) };
        if song.is_null() {
            None
        } else {
            Some(MpdSong { song: song })
        }
    }

    pub fn move_to(&mut self, pos: uint, song: &MpdSong) -> MpdResult<()> {
        if unsafe { mpd_run_move_id(self.conn.conn, song.id(), pos as libc::c_uint) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }

    pub fn swap<T: ToSongPos>(&mut self, song1: T, song2: T) -> MpdResult<()> {
        if unsafe { mpd_run_swap(self.conn.conn, song1.song_pos(), song2.song_pos()) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }
}

trait ToSongPos {
    fn song_pos(&self) -> uint;
}

impl ToSongPos for uint {
    #[inline] fn song_pos(&self) -> uint { *self }
}

impl ToSongPos for MpdSong {
    #[inline] fn song_pos(&self) -> uint { self.pos() }
}
<commit_msg>generalized push/insert/swap/swap_id for queue<commit_after>
use error::MpdResult;
use connection::{FromConn, MpdConnection, mpd_connection};
use songs::{MpdSong, mpd_song};
use std::c_str::CString;
use libc;

extern {
    fn mpd_run_get_queue_song_pos(connection: *mut mpd_connection, pos: libc::c_uint) -> *mut mpd_song;
    fn mpd_run_move_id(connection: *mut mpd_connection, from: libc::c_uint, to: libc::c_uint) -> bool;
    fn mpd_run_swap_id(connection: *mut mpd_connection, id1: libc::c_uint, id2: libc::c_uint) -> bool;
    fn mpd_run_swap(connection: *mut mpd_connection, pos1: libc::c_uint, pos2: libc::c_uint) -> bool;
    fn mpd_run_add_id(connection: *mut mpd_connection, file: *const i8) -> libc::c_int;
    fn mpd_run_add_id_to(connection: *mut mpd_connection, uri: *const i8, to: libc::c_uint) -> libc::c_int;
}

pub struct MpdQueue<'a> {
    conn: &'a MpdConnection
}

impl<'a> MpdQueue<'a> {
    pub fn from_conn(conn: &'a MpdConnection) -> MpdQueue<'a> {
        MpdQueue { conn: conn }
    }

    pub fn get(&self, index: uint) -> Option<MpdSong> {
        let song = unsafe { mpd_run_get_queue_song_pos(self.conn.conn, index as libc::c_uint) };
        if song.is_null() {
            None
        } else {
            Some(MpdSong { song: song })
        }
    }

    pub fn move_to(&mut self, pos: uint, song: &MpdSong) -> MpdResult<()> {
        if unsafe { mpd_run_move_id(self.conn.conn, song.id(), pos as libc::c_uint) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }

    pub fn insert<T: ToSongUri>(&mut self, pos: uint, song: &T) -> MpdResult<uint> {
        let uid = unsafe { mpd_run_add_id_to(self.conn.conn, song.song_uri().as_ptr(), pos as libc::c_uint) };
        if uid < 0 {
            Err(FromConn::from_conn(self.conn).unwrap())
        } else {
            Ok(uid as uint)
        }
    }

    pub fn push<T: ToSongUri>(&mut self, song: &T) -> MpdResult<uint> {
        let uid = unsafe { mpd_run_add_id(self.conn.conn, song.song_uri().as_ptr()) };
        if uid < 0 {
            Err(FromConn::from_conn(self.conn).unwrap())
        } else {
            Ok(uid as uint)
        }
    }

    pub fn swap_id(&mut self, song1: &MpdSong, song2: &MpdSong) -> MpdResult<()> {
        if unsafe { mpd_run_swap_id(self.conn.conn, song1.id() as libc::c_uint, song2.id() as libc::c_uint) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }

    pub fn swap<T: ToSongPos>(&mut self, song1: T, song2: T) -> MpdResult<()> {
        if unsafe { mpd_run_swap(self.conn.conn, song1.song_pos() as libc::c_uint, song2.song_pos() as libc::c_uint) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }
}

pub trait ToSongPos {
    fn song_pos(&self) -> uint;
}

impl ToSongPos for uint {
    #[inline] fn song_pos(&self) -> uint { *self }
}

impl ToSongPos for MpdSong {
    #[inline] fn song_pos(&self) -> uint { self.pos() }
}

pub trait ToSongUri {
    fn song_uri(&self) -> CString;
}

impl ToSongUri for MpdSong {
    #[inline] fn song_uri(&self) -> CString {
        self.uri().to_c_str()
    }
}

impl ToSongUri for String {
    #[inline] fn song_uri(&self) -> CString {
        self.to_c_str()
    }
}
<|endoftext|>


<commit_before>use super::{SeasonState, SeriesConfig};
use crate::backend::{AnimeEntry, AnimeInfo, SyncBackend};
use crate::error::SeriesError;
use crate::input::{self, Answer};
use lazy_static::lazy_static;
use regex::Regex;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs;
use std::ops::Range;
use std::path::{Path, PathBuf};
use toml;

pub struct FolderData {
    pub series_info: SeriesInfo,
    pub savefile: SaveData,
    pub subseries: String,
    pub path: PathBuf,
}

impl FolderData {
    const DEFAULT_SUBSERIES_NAME: &'static str = "main";

    pub fn load_dir(path: &Path, subseries: Option<String>) -> Result<FolderData, SeriesError> {
        let subseries = subseries.unwrap_or_else(|| FolderData::DEFAULT_SUBSERIES_NAME.into());

        let mut savefile = SaveData::from_dir(path)?;
        let series_info = FolderData::load_series_info(path, &mut savefile, &subseries)?;

        Ok(FolderData {
            series_info,
            savefile,
            subseries,
            path: PathBuf::from(path),
        })
    }

    fn load_series_info(
        path: &Path,
        savefile: &mut SaveData,
        subseries: &str,
    ) -> Result<SeriesInfo, SeriesError> {
        let mut ep_data = parse_episode_files_until_valid(path, &mut savefile.episode_matcher)?;
        let subseries_data = savefile.get_mut_subseries_entry(subseries);

        if let Some(info) = SeriesInfo::select_from_subseries(&mut ep_data, &subseries_data)? {
            return Ok(info);
        }

        let info = SeriesInfo::prompt_select_from_episodes(ep_data)?;
        subseries_data.files_title = Some(info.name.clone());

        Ok(info)
    }

    pub fn populate_season_data<B>(&mut self, config: &SeriesConfig<B>) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        let num_seasons = self.seasons().len();

        if num_seasons > config.season_num {
            return Ok(());
        }

        for cur_season in num_seasons..=config.season_num {
            let info = AnimeInfo::default();
            let entry = AnimeEntry::new(info);

            let mut season = SeasonState {
                state: entry,
                needs_info: true,
                needs_sync: config.offline_mode,
            };

            season.sync_info_from_remote(config, &self, cur_season)?;

            let subseries = self
                .savefile
                .get_mut_subseries_entry(self.subseries.clone());

            subseries.season_states.push(season);
        }

        Ok(())
    }

    pub fn calculate_season_offset(&self, range: Range<usize>) -> Option<u32> {
        let seasons = self.seasons();
        let num_seasons = seasons.len();

        if range.end >= num_seasons {
            return None;
        }

        let mut offset = 0;

        for i in range {
            let season = &seasons[i];

            match season.state.info.episodes {
                Some(eps) => offset += eps,
                None => return Some(offset),
            }
        }

        Some(offset)
    }

    pub fn delete_series_dir(&self) -> Result<(), SeriesError> {
        println!("WARNING: {} will be deleted", self.path.to_string_lossy());
        println!("is this ok? (y/N)");

        if !input::read_yn(Answer::No)? {
            return Ok(());
        }

        fs::remove_dir_all(&self.path)?;
        Ok(())
    }

    pub fn get_episode(&self, episode: u32) -> Result<&PathBuf, SeriesError> {
        self.series_info.get_episode(episode)
    }

    pub fn save(&self) -> Result<(), SeriesError> {
        self.savefile.write_to_file()
    }

    pub fn seasons(&self) -> &Vec<SeasonState> {
        &self.savefile.subseries[&self.subseries].season_states
    }

    pub fn seasons_mut(&mut self) -> &mut Vec<SeasonState> {
        &mut self
            .savefile
            .get_mut_subseries_entry(self.subseries.clone())
            .season_states
    }
}

pub type SubSeriesName = String;

#[derive(Serialize, Deserialize)]
pub struct SaveData {
    pub episode_matcher: Option<String>,
    #[serde(flatten)]
    pub subseries: HashMap<SubSeriesName, SubSeriesData>,
    #[serde(skip)]
    pub path: PathBuf,
}

impl SaveData {
    const DATA_FILE_NAME: &'static str = ".anup";

    pub fn new(path: PathBuf) -> SaveData {
        SaveData {
            episode_matcher: None,
            subseries: HashMap::new(),
            path,
        }
    }

    pub fn get_mut_subseries_entry<S>(&mut self, name: S) -> &mut SubSeriesData
    where
        S: Into<String>,
    {
        self.subseries
            .entry(name.into())
            .or_insert_with(SubSeriesData::new)
    }

    pub fn from_dir(path: &Path) -> Result<SaveData, SeriesError> {
        let path = PathBuf::from(path).join(SaveData::DATA_FILE_NAME);

        if !path.exists() {
            return Ok(SaveData::new(path));
        }

        let file_contents = fs::read_to_string(&path)?;

        let mut save_data: SaveData = toml::from_str(&file_contents)?;
        save_data.path = path;

        Ok(save_data)
    }

    pub fn write_to_file(&self) -> Result<(), SeriesError> {
        let toml = toml::to_string(self)?;
        fs::write(&self.path, toml)?;

        Ok(())
    }
}

#[derive(Serialize, Deserialize)]
pub struct SubSeriesData {
    pub files_title: Option<String>,
    pub season_states: Vec<SeasonState>,
}

impl SubSeriesData {
    pub fn new() -> SubSeriesData {
        SubSeriesData {
            files_title: None,
            season_states: Vec::new(),
        }
    }
}

pub type EpisodePaths = HashMap<u32, PathBuf>;
pub type SeriesEpisodes = HashMap<String, EpisodePaths>;

pub struct SeriesInfo {
    pub name: String,
    pub episodes: HashMap<u32, PathBuf>,
}

impl SeriesInfo {
    pub fn get_episode(&self, episode: u32) -> Result<&PathBuf, SeriesError> {
        self.episodes
            .get(&episode)
            .ok_or_else(|| SeriesError::EpisodeNotFound(episode))
    }

    pub fn select_from_subseries(
        ep_data: &mut SeriesEpisodes,
        subseries: &SubSeriesData,
    ) -> Result<Option<SeriesInfo>, SeriesError> {
        if let Some(name) = &subseries.files_title {
            let entry = ep_data.remove_entry(name);

            match entry {
                Some((name, episodes)) => return Ok(Some(SeriesInfo { name, episodes })),
                None => return Err(SeriesError::NoSeriesEpisodes),
            }
        }

        Ok(None)
    }

    pub fn prompt_select_from_episodes(info: SeriesEpisodes) -> Result<SeriesInfo, SeriesError> {
        if info.is_empty() {
            return Err(SeriesError::NoSeriesFound);
        }

        let mut info = info
            .into_iter()
            .map(|(name, eps)| SeriesInfo {
                name,
                episodes: eps,
            })
            .collect::<Vec<_>>();

        if info.len() == 1 {
            return Ok(info.swap_remove(0));
        }

        println!("multiple series found in directory");
        println!("please enter the number next to the episode files you want to use:");

        for (i, series) in info.iter().enumerate() {
            println!("{} [{}]", 1 + i, series.name);
        }

        let index = input::read_range(1, info.len())? - 1;
        let series = info.swap_remove(index);

        Ok(series)
    }
}

struct EpisodeFile {
    series_name: String,
    episode_num: u32,
}

impl EpisodeFile {
    fn parse(path: &Path, matcher: &Regex) -> Result<EpisodeFile, SeriesError> {
        // Replace certain characters with spaces since they can prevent proper series
        // identification or prevent it from being found on a sync backend
        let filename = path
            .file_name()
            .and_then(|path| path.to_str())
            .ok_or(SeriesError::UnableToGetFilename)?;

        let caps = matcher
            .captures(&filename)
            .ok_or(SeriesError::EpisodeRegexCaptureFailed)?;

        let series_name = caps
            .name("name")
            .ok_or_else(|| SeriesError::UnknownRegexCapture("name".into()))
            .map(|name| EpisodeFile::cleanup_title(name.as_str()))?;

        let episode = match caps.name("episode") {
            Some(capture) => capture
                .as_str()
                .parse()
                .map_err(SeriesError::EpisodeNumParseFailed)?,
            None => 1,
        };

        Ok(EpisodeFile {
            series_name,
            episode_num: episode,
        })
    }

    fn cleanup_title(title: &str) -> String {
        let mut clean_title = String::from(title);
        let bytes = unsafe { clean_title.as_bytes_mut() };

        for byte in bytes {
            match byte {
                b'.' | b'_' => *byte = b' ',
                _ => (),
            }
        }

        clean_title.trim_right().to_string()
    }
}

// This default pattern will match episodes in several common formats, such as:
// [Group] Series Name - 01.mkv
// [Group]_Series_Name_-_01.mkv
// [Group].Series.Name.-.01.mkv
// [Group] Series Name - 01 [tag 1][tag 2].mkv
// [Group]_Series_Name_-_01_[tag1][tag2].mkv
// [Group].Series.Name.-.01.[tag1][tag2].mkv
// Series Name - 01.mkv
// Series_Name_-_01.mkv
// Series.Name.-.01.mkv
const EP_FORMAT_REGEX: &str =
    r"(?:\[.+?\](?:_+|\.+|\s*))?(?P<name>.+)(?:\s*|_*|\.*)(?:-|\.|_).*?(?P<episode>\d+)";

fn format_episode_parser_regex<'a, S>(pattern: Option<S>) -> Result<Cow<'a, Regex>, SeriesError>
where
    S: AsRef<str>,
{
    lazy_static! {
        static ref EP_FORMAT: Regex = Regex::new(EP_FORMAT_REGEX).unwrap();
    }

    match pattern {
        Some(pattern) => {
            let pattern = pattern
                .as_ref()
                .replace("{name}", "(?P<name>.+?)")
                .replace("{episode}", r"(?P<episode>\d+)");

            let regex = Regex::new(&pattern)?;
            Ok(Cow::Owned(regex))
        }
        None => Ok(Cow::Borrowed(&*EP_FORMAT)),
    }
}

pub fn parse_episode_files<S>(
    path: &Path,
    pattern: Option<S>,
) -> Result<SeriesEpisodes, SeriesError>
where
    S: AsRef<str>,
{
    if !path.is_dir() {
        return Err(SeriesError::NotADirectory(path.to_string_lossy().into()));
    }

    let pattern = format_episode_parser_regex(pattern)?;
    let mut data = HashMap::with_capacity(1);

    for entry in fs::read_dir(path).map_err(SeriesError::Io)? {
        let entry = entry.map_err(SeriesError::Io)?.path();

        if !entry.is_file() {
            continue;
        }

        let episode = match EpisodeFile::parse(&entry, pattern.as_ref()) {
            Ok(episode) => episode,
            Err(SeriesError::EpisodeRegexCaptureFailed) => continue,
            Err(err) => return Err(err),
        };

        let series = data
            .entry(episode.series_name)
            .or_insert_with(|| HashMap::with_capacity(1));

        series.insert(episode.episode_num, entry);
    }

    if data.is_empty() {
        return Err(SeriesError::NoSeriesFound);
    }

    Ok(data)
}

pub fn parse_episode_files_until_valid<S>(
    path: &Path,
    pattern: &mut Option<S>,
) -> Result<SeriesEpisodes, SeriesError>
where
    S: AsRef<str> + From<String>,
{
    loop {
        match parse_episode_files(path, pattern.as_ref()) {
            Ok(data) => return Ok(data),
            Err(SeriesError::NoSeriesFound) => {
                eprintln!("error: no series found");
                println!("you will now be prompted to enter a custom regex pattern");
                println!("when entering the pattern, please mark the series name and episode number with {{name}} and {{episode}}, respectively");
                println!("note: if you're trying to play a single file (like a movie) and it doesn't have an episode number, you can omit the {{episode}} marker");
                println!("example:");
                println!("  filename: [SubGroup] Series Name - Ep01 [1080p].mkv");
                println!(r"  pattern: \[.+?\] {{name}} - Ep{{episode}} \[1080p\].mkv");
                println!("please enter your custom pattern:");
            }
            Err(err @ SeriesError::Regex(_)) | Err(err @ SeriesError::UnknownRegexCapture(_)) => {
                eprintln!("error parsing regex pattern: {}", err);
                println!("please try again:");
            }
            Err(err) => return Err(err),
        }

        let line = input::read_line()?;
        *pattern = Some(line.into());
    }
}
<commit_msg>[series] Ignore episode files with .part extension<commit_after>use super::{SeasonState, SeriesConfig};
use crate::backend::{AnimeEntry, AnimeInfo, SyncBackend};
use crate::error::SeriesError;
use crate::input::{self, Answer};
use lazy_static::lazy_static;
use regex::Regex;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs;
use std::ops::Range;
use std::path::{Path, PathBuf};
use toml;

pub struct FolderData {
    pub series_info: SeriesInfo,
    pub savefile: SaveData,
    pub subseries: String,
    pub path: PathBuf,
}

impl FolderData {
    const DEFAULT_SUBSERIES_NAME: &'static str = "main";

    pub fn load_dir(path: &Path, subseries: Option<String>) -> Result<FolderData, SeriesError> {
        let subseries = subseries.unwrap_or_else(|| FolderData::DEFAULT_SUBSERIES_NAME.into());

        let mut savefile = SaveData::from_dir(path)?;
        let series_info = FolderData::load_series_info(path, &mut savefile, &subseries)?;

        Ok(FolderData {
            series_info,
            savefile,
            subseries,
            path: PathBuf::from(path),
        })
    }

    fn load_series_info(
        path: &Path,
        savefile: &mut SaveData,
        subseries: &str,
    ) -> Result<SeriesInfo, SeriesError> {
        let mut ep_data = parse_episode_files_until_valid(path, &mut savefile.episode_matcher)?;
        let subseries_data = savefile.get_mut_subseries_entry(subseries);

        if let Some(info) = SeriesInfo::select_from_subseries(&mut ep_data, &subseries_data)? {
            return Ok(info);
        }

        let info = SeriesInfo::prompt_select_from_episodes(ep_data)?;
        subseries_data.files_title = Some(info.name.clone());

        Ok(info)
    }

    pub fn populate_season_data<B>(&mut self, config: &SeriesConfig<B>) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        let num_seasons = self.seasons().len();

        if num_seasons > config.season_num {
            return Ok(());
        }

        for cur_season in num_seasons..=config.season_num {
            let info = AnimeInfo::default();
            let entry = AnimeEntry::new(info);

            let mut season = SeasonState {
                state: entry,
                needs_info: true,
                needs_sync: config.offline_mode,
            };

            season.sync_info_from_remote(config, &self, cur_season)?;

            let subseries = self
                .savefile
                .get_mut_subseries_entry(self.subseries.clone());

            subseries.season_states.push(season);
        }

        Ok(())
    }

    pub fn calculate_season_offset(&self, range: Range<usize>) -> Option<u32> {
        let seasons = self.seasons();
        let num_seasons = seasons.len();

        if range.end >= num_seasons {
            return None;
        }

        let mut offset = 0;

        for i in range {
            let season = &seasons[i];

            match season.state.info.episodes {
                Some(eps) => offset += eps,
                None => return Some(offset),
            }
        }

        Some(offset)
    }

    pub fn delete_series_dir(&self) -> Result<(), SeriesError> {
        println!("WARNING: {} will be deleted", self.path.to_string_lossy());
        println!("is this ok? (y/N)");

        if !input::read_yn(Answer::No)? {
            return Ok(());
        }

        fs::remove_dir_all(&self.path)?;
        Ok(())
    }

    pub fn get_episode(&self, episode: u32) -> Result<&PathBuf, SeriesError> {
        self.series_info.get_episode(episode)
    }

    pub fn save(&self) -> Result<(), SeriesError> {
        self.savefile.write_to_file()
    }

    pub fn seasons(&self) -> &Vec<SeasonState> {
        &self.savefile.subseries[&self.subseries].season_states
    }

    pub fn seasons_mut(&mut self) -> &mut Vec<SeasonState> {
        &mut self
            .savefile
            .get_mut_subseries_entry(self.subseries.clone())
            .season_states
    }
}

pub type SubSeriesName = String;

#[derive(Serialize, Deserialize)]
pub struct SaveData {
    pub episode_matcher: Option<String>,
    #[serde(flatten)]
    pub subseries: HashMap<SubSeriesName, SubSeriesData>,
    #[serde(skip)]
    pub path: PathBuf,
}

impl SaveData {
    const DATA_FILE_NAME: &'static str = ".anup";

    pub fn new(path: PathBuf) -> SaveData {
        SaveData {
            episode_matcher: None,
            subseries: HashMap::new(),
            path,
        }
    }

    pub fn get_mut_subseries_entry<S>(&mut self, name: S) -> &mut SubSeriesData
    where
        S: Into<String>,
    {
        self.subseries
            .entry(name.into())
            .or_insert_with(SubSeriesData::new)
    }

    pub fn from_dir(path: &Path) -> Result<SaveData, SeriesError> {
        let path = PathBuf::from(path).join(SaveData::DATA_FILE_NAME);

        if !path.exists() {
            return Ok(SaveData::new(path));
        }

        let file_contents = fs::read_to_string(&path)?;

        let mut save_data: SaveData = toml::from_str(&file_contents)?;
        save_data.path = path;

        Ok(save_data)
    }

    pub fn write_to_file(&self) -> Result<(), SeriesError> {
        let toml = toml::to_string(self)?;
        fs::write(&self.path, toml)?;

        Ok(())
    }
}

#[derive(Serialize, Deserialize)]
pub struct SubSeriesData {
    pub files_title: Option<String>,
    pub season_states: Vec<SeasonState>,
}

impl SubSeriesData {
    pub fn new() -> SubSeriesData {
        SubSeriesData {
            files_title: None,
            season_states: Vec::new(),
        }
    }
}

pub type EpisodePaths = HashMap<u32, PathBuf>;
pub type SeriesEpisodes = HashMap<String, EpisodePaths>;

pub struct SeriesInfo {
    pub name: String,
    pub episodes: HashMap<u32, PathBuf>,
}

impl SeriesInfo {
    pub fn get_episode(&self, episode: u32) -> Result<&PathBuf, SeriesError> {
        self.episodes
            .get(&episode)
            .ok_or_else(|| SeriesError::EpisodeNotFound(episode))
    }

    pub fn select_from_subseries(
        ep_data: &mut SeriesEpisodes,
        subseries: &SubSeriesData,
    ) -> Result<Option<SeriesInfo>, SeriesError> {
        if let Some(name) = &subseries.files_title {
            let entry = ep_data.remove_entry(name);

            match entry {
                Some((name, episodes)) => return Ok(Some(SeriesInfo { name, episodes })),
                None => return Err(SeriesError::NoSeriesEpisodes),
            }
        }

        Ok(None)
    }

    pub fn prompt_select_from_episodes(info: SeriesEpisodes) -> Result<SeriesInfo, SeriesError> {
        if info.is_empty() {
            return Err(SeriesError::NoSeriesFound);
        }

        let mut info = info
            .into_iter()
            .map(|(name, eps)| SeriesInfo {
                name,
                episodes: eps,
            })
            .collect::<Vec<_>>();

        if info.len() == 1 {
            return Ok(info.swap_remove(0));
        }

        println!("multiple series found in directory");
        println!("please enter the number next to the episode files you want to use:");

        for (i, series) in info.iter().enumerate() {
            println!("{} [{}]", 1 + i, series.name);
        }

        let index = input::read_range(1, info.len())? - 1;
        let series = info.swap_remove(index);

        Ok(series)
    }
}

struct EpisodeFile {
    series_name: String,
    episode_num: u32,
}

impl EpisodeFile {
    fn parse(path: &Path, matcher: &Regex) -> Result<EpisodeFile, SeriesError> {
        // Replace certain characters with spaces since they can prevent proper series
        // identification or prevent it from being found on a sync backend
        let filename = path
            .file_name()
            .and_then(|path| path.to_str())
            .ok_or(SeriesError::UnableToGetFilename)?;

        let caps = matcher
            .captures(&filename)
            .ok_or(SeriesError::EpisodeRegexCaptureFailed)?;

        let series_name = caps
            .name("name")
            .ok_or_else(|| SeriesError::UnknownRegexCapture("name".into()))
            .map(|name| EpisodeFile::cleanup_title(name.as_str()))?;

        let episode = match caps.name("episode") {
            Some(capture) => capture
                .as_str()
                .parse()
                .map_err(SeriesError::EpisodeNumParseFailed)?,
            None => 1,
        };

        Ok(EpisodeFile {
            series_name,
            episode_num: episode,
        })
    }

    fn cleanup_title(title: &str) -> String {
        let mut clean_title = String::from(title);
        let bytes = unsafe { clean_title.as_bytes_mut() };

        for byte in bytes {
            match byte {
                b'.' | b'_' => *byte = b' ',
                _ => (),
            }
        }

        clean_title.trim_right().to_string()
    }
}

// This default pattern will match episodes in several common formats, such as:
// [Group] Series Name - 01.mkv
// [Group]_Series_Name_-_01.mkv
// [Group].Series.Name.-.01.mkv
// [Group] Series Name - 01 [tag 1][tag 2].mkv
// [Group]_Series_Name_-_01_[tag1][tag2].mkv
// [Group].Series.Name.-.01.[tag1][tag2].mkv
// Series Name - 01.mkv
// Series_Name_-_01.mkv
// Series.Name.-.01.mkv
const EP_FORMAT_REGEX: &str =
    r"(?:\[.+?\](?:_+|\.+|\s*))?(?P<name>.+)(?:\s*|_*|\.*)(?:-|\.|_).*?(?P<episode>\d+)";

fn format_episode_parser_regex<'a, S>(pattern: Option<S>) -> Result<Cow<'a, Regex>, SeriesError>
where
    S: AsRef<str>,
{
    lazy_static! {
        static ref EP_FORMAT: Regex = Regex::new(EP_FORMAT_REGEX).unwrap();
    }

    match pattern {
        Some(pattern) => {
            let pattern = pattern
                .as_ref()
                .replace("{name}", "(?P<name>.+?)")
                .replace("{episode}", r"(?P<episode>\d+)");

            let regex = Regex::new(&pattern)?;
            Ok(Cow::Owned(regex))
        }
        None => Ok(Cow::Borrowed(&*EP_FORMAT)),
    }
}

pub fn parse_episode_files<S>(
    path: &Path,
    pattern: Option<S>,
) -> Result<SeriesEpisodes, SeriesError>
where
    S: AsRef<str>,
{
    if !path.is_dir() {
        return Err(SeriesError::NotADirectory(path.to_string_lossy().into()));
    }

    let pattern = format_episode_parser_regex(pattern)?;
    let mut data = HashMap::with_capacity(1);

    for entry in fs::read_dir(path).map_err(SeriesError::Io)? {
        let entry = entry.map_err(SeriesError::Io)?.path();

        if !entry.is_file() {
            continue;
        }

        // Skip files with a .part extension as they are most likely being downloaded
        if let Some(extension) = entry.extension() {
            if extension == "part" {
                continue;
            }
        }

        let episode = match EpisodeFile::parse(&entry, pattern.as_ref()) {
            Ok(episode) => episode,
            Err(SeriesError::EpisodeRegexCaptureFailed) => continue,
            Err(err) => return Err(err),
        };

        let series = data
            .entry(episode.series_name)
            .or_insert_with(|| HashMap::with_capacity(1));

        series.insert(episode.episode_num, entry);
    }

    if data.is_empty() {
        return Err(SeriesError::NoSeriesFound);
    }

    Ok(data)
}

pub fn parse_episode_files_until_valid<S>(
    path: &Path,
    pattern: &mut Option<S>,
) -> Result<SeriesEpisodes, SeriesError>
where
    S: AsRef<str> + From<String>,
{
    loop {
        match parse_episode_files(path, pattern.as_ref()) {
            Ok(data) => return Ok(data),
            Err(SeriesError::NoSeriesFound) => {
                eprintln!("error: no series found");
                println!("you will now be prompted to enter a custom regex pattern");
                println!("when entering the pattern, please mark the series name and episode number with {{name}} and {{episode}}, respectively");
                println!("note: if you're trying to play a single file (like a movie) and it doesn't have an episode number, you can omit the {{episode}} marker");
                println!("example:");
                println!("  filename: [SubGroup] Series Name - Ep01 [1080p].mkv");
                println!(r"  pattern: \[.+?\] {{name}} - Ep{{episode}} \[1080p\].mkv");
                println!("please enter your custom pattern:");
            }
            Err(err @ SeriesError::Regex(_)) | Err(err @ SeriesError::UnknownRegexCapture(_)) => {
                eprintln!("error parsing regex pattern: {}", err);
                println!("please try again:");
            }
            Err(err) => return Err(err),
        }

        let line = input::read_line()?;
        *pattern = Some(line.into());
    }
}
<|endoftext|>


<commit_before>// DOCS

#![allow(unstable)]
#![feature(plugin)]
#[plugin] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components
      component_end {
        let mut rv = Component::new(name);
        rv.subcomponents = cs;

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> String
    = "BEGIN:" v:value __ { v.to_string() }

component_end -> String
    = "END:" v:value __ { v.to_string() }

components -> Vec<Component>
    = cs:component ** eols __ { cs }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

prop -> (&'input str, Property)
    = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
        (k, Property { params: p, raw_value: v, prop_group: g })
    }

group -> String
    = g:group_name "." { g }

group_name -> String
    = group_char+ { match_str.to_string() }

name -> &'input str
    = iana_token+ { match_str }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
        rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
        rv
    }

param -> (&'input str, &'input str)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => ""
        })
    }

param_name -> &'input str
    = iana_token+ { match_str }

param_value -> &'input str
    = x:(quoted_string / param_text) { x }

param_text -> &'input str
    = safe_char* { match_str }

value -> String
    = value_char+ { match_str.to_string() }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    parser::component(unfolded.as_slice())
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}
<commit_msg>bugfixes<commit_after>// DOCS

#![allow(unstable)]
#![feature(plugin)]
#[plugin] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components
      component_end {
        let mut rv = Component::new(name);
        rv.subcomponents = cs;

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> &'input str
    = "BEGIN:" v:value __ { v }

component_end -> &'input str
    = "END:" v:value __ { v }

components -> Vec<Component>
    = cs:component ** eols __ { cs }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

prop -> (&'input str, Property)
    = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
        (k, Property { params: p, raw_value: v.to_string(), prop_group: g })
    }

group -> String
    = g:group_name "." { g.to_string() }

group_name -> &'input str
    = group_char+ { match_str }

name -> &'input str
    = iana_token+ { match_str }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
        rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
        rv
    }

param -> (&'input str, &'input str)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => ""
        })
    }

param_name -> &'input str
    = iana_token+ { match_str }

param_value -> &'input str
    = x:(quoted_string / param_text) { x }

param_text -> &'input str
    = safe_char* { match_str }

value -> &'input str
    = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    parser::component(unfolded.as_slice())
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}
<|endoftext|>


<commit_before>#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;

use proc_macro::{TokenStream, quote};

#[proc_macro_derive(ClippyMiniMacroTest)]
pub fn mini_macro(_: TokenStream) -> TokenStream {
    quote!(
        #[allow(unused)] fn needless_take_by_value(s: String) { println!("{}", s.len()); }
    )
}<commit_msg>Update mini-macro post proc macro stabilization<commit_after>#![feature(use_extern_macros, proc_macro_quote, proc_macro_non_items)]
extern crate proc_macro;

use proc_macro::{TokenStream, quote};

#[proc_macro_derive(ClippyMiniMacroTest)]
pub fn mini_macro(_: TokenStream) -> TokenStream {
    quote!(
        #[allow(unused)] fn needless_take_by_value(s: String) { println!("{}", s.len()); }
    )
}<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.

use num::One;

use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde;
use core::fmt;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::marker::PhantomData;
use {Point2D, Rect, Size2D, Vector2D};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Point2D::new(point.x * self.get(), point.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Vector2D::new(vec.x * self.get(), vec.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Size2D::new(size.width * self.get(), size.height * self.get())
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
        where T: Copy + Mul
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns the inverse of this scale.
    #[inline]
    pub fn inverse(&self) -> Scale<T::Output, Dst, Src>
        where T: Clone + Neg
    {
        Scale::new(-self.get())
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// ```
    #[inline]
    pub fn is_identity(&self) -> bool
        where T: PartialEq + One
    {
        self.0 == T::one()
    }
}

impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub fn get(&self) -> T {
        self.0.clone()
    }
}

impl<Src, Dst> Scale<f32, Src, Dst> {
    /// Identity scaling, could be used to safely transit from one space to another.
    pub const ONE: Self = Scale(1.0, PhantomData);
}

impl<T: Clone + One + Div<T, Output = T>, Src, Dst> Scale<T, Src, Dst> {
    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inv(), Scale::new(10.0));
    /// ```
    pub fn inv(&self) -> Scale<T, Dst, Src> {
        let one: T = One::one();
        Scale::new(one / self.get())
    }
}

// scale0 * scale1
impl<T: Mul<T, Output = T>, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T, A, C>;
    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Scale<T, A, C> {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add<T, Output = T>, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T, Src, Dst>;
    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub<T, Output = T>, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T, Src, Dst>;
    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
        Scale::new(self.0 - other.0)
    }
}

impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.get()).map(Scale::new)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.get())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: fmt::Display, Src, Dst> fmt::Display for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inv();
        assert_eq!(mm_per_cm.get(), 10.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert!(a != b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<commit_msg>Scale: move inv() into Clone impl block and relax requirements to types<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.

use num::One;

use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde;
use core::fmt;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::marker::PhantomData;
use {Point2D, Rect, Size2D, Vector2D};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Point2D::new(point.x * self.get(), point.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Vector2D::new(vec.x * self.get(), vec.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
        where T: Clone + Mul
    {
        Size2D::new(size.width * self.get(), size.height * self.get())
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
        where T: Copy + Mul
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns the inverse of this scale.
    #[inline]
    pub fn inverse(&self) -> Scale<T::Output, Dst, Src>
        where T: Clone + Neg
    {
        Scale::new(-self.get())
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// ```
    #[inline]
    pub fn is_identity(&self) -> bool
        where T: PartialEq + One
    {
        self.0 == T::one()
    }
}

impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub fn get(&self) -> T {
        self.0.clone()
    }

    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inv(), Scale::new(10.0));
    /// ```
    pub fn inv(&self) -> Scale<T::Output, Dst, Src>
    where
        T: One + Div
    {
        let one: T = One::one();
        Scale::new(one / self.0.clone())
    }
}

impl<Src, Dst> Scale<f32, Src, Dst> {
    /// Identity scaling, could be used to safely transit from one space to another.
    pub const ONE: Self = Scale(1.0, PhantomData);
}

// scale0 * scale1
impl<T: Mul<T, Output = T>, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T, A, C>;
    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Scale<T, A, C> {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add<T, Output = T>, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T, Src, Dst>;
    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub<T, Output = T>, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T, Src, Dst>;
    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
        Scale::new(self.0 - other.0)
    }
}

impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.get()).map(Scale::new)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.get())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: fmt::Display, Src, Dst> fmt::Display for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inv();
        assert_eq!(mm_per_cm.get(), 10.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert!(a != b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<|endoftext|>


<commit_before>use super::{Icon,IconScraper};
use std::str::FromStr;

pub trait Strategy {
    fn get_guesses(self, &mut IconScraper) -> Vec<Icon>;
}

pub struct DefaultFaviconPathStrategy;
impl DefaultFaviconPathStrategy {
    fn get_uneducated_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        let mut current = parser.document_url.clone();
        let mut rv = vec![];

        loop {
            {
                let mut path = current.path_mut().unwrap();
                path.pop();
                path.push("favicon.ico".to_owned());
            }

            let icon = Icon::from_url(current.clone());

            rv.push(icon);

            {
                let mut path = current.path_mut().unwrap();
                path.pop().unwrap();
                if path.len() == 0 {
                    break;
                }
            }
        }
        rv
    }
}
impl Strategy for DefaultFaviconPathStrategy {
    fn get_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        for mut icon in self.get_uneducated_guesses(parser).into_iter() {
            if icon.fetch_dimensions().is_ok() {
                return vec![icon];
            }
        }
        vec![]
    }
}

pub struct LinkRelStrategy;
impl Strategy for LinkRelStrategy {
    fn get_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        parser.dom.as_ref().unwrap().select("link[rel=icon], link[rel=apple-touch-icon]").unwrap()
            .filter_map(|data| {
                let attrs = data.attributes.borrow();
                let href = match attrs.get(&qualname!("", "href")) {
                    Some(x) => x,
                    None => return None
                };
                let icon_url = match parser.document_url.join(href) {
                    Ok(x) => x,
                    Err(_) => return None
                };

                let mut sizes = match attrs.get(&qualname!("", "sizes")) {
                    Some(s) => s.split('x').filter_map(|d| u32::from_str(d).ok()),
                    None => return None
                };

                let (x, y) = match (sizes.next(), sizes.next()) {
                    (Some(x), Some(y)) => (Some(x), Some(y)),
                    _ => return None
                };

                Some({
                    let mut icon = Icon::from_url(icon_url);
                    icon.width = x;
                    icon.height = y;
                    icon
                })
            })
            .collect()
    }
}

#[test]
fn test_default_favicon_paths() {
    use url;
    let mut x = IconScraper::from_url(
        url::Url::parse("http://example.com/a/b/c/d/e/f").unwrap()
    );
    let s = DefaultFaviconPathStrategy;
    let paths = s.get_uneducated_guesses(&mut x)
        .into_iter()
        .map(|u| u.url.serialize_path().unwrap())
        .collect::<Vec<String>>();

    assert_eq!(paths, vec![
        "/a/b/c/d/e/favicon.ico",
        "/a/b/c/d/favicon.ico",
        "/a/b/c/favicon.ico",
        "/a/b/favicon.ico",
        "/a/favicon.ico",
        "/favicon.ico",
    ]);
}
<commit_msg>Use kuchiki's improvements in #17<commit_after>use super::{Icon,IconScraper};
use std::str::FromStr;

pub trait Strategy {
    fn get_guesses(self, &mut IconScraper) -> Vec<Icon>;
}

pub struct DefaultFaviconPathStrategy;
impl DefaultFaviconPathStrategy {
    fn get_uneducated_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        let mut current = parser.document_url.clone();
        let mut rv = vec![];

        loop {
            {
                let mut path = current.path_mut().unwrap();
                path.pop();
                path.push("favicon.ico".to_owned());
            }

            let icon = Icon::from_url(current.clone());
            rv.push(icon);

            {
                let mut path = current.path_mut().unwrap();
                path.pop().unwrap();
                if path.len() == 0 {
                    break;
                }
            }
        }
        rv
    }
}
impl Strategy for DefaultFaviconPathStrategy {
    fn get_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        for mut icon in self.get_uneducated_guesses(parser).into_iter() {
            if icon.fetch_dimensions().is_ok() {
                return vec![icon];
            }
        }
        vec![]
    }
}

pub struct LinkRelStrategy;
impl Strategy for LinkRelStrategy {
    fn get_guesses(self, parser: &mut IconScraper) -> Vec<Icon> {
        parser.dom.as_ref().unwrap().select("link[rel=icon], link[rel=apple-touch-icon]").unwrap()
            .filter_map(|data| {
                let attrs = data.attributes.borrow();
                let href = match attrs.get(atom!("href")) {
                    Some(x) => x,
                    None => return None
                };
                let icon_url = match parser.document_url.join(href) {
                    Ok(x) => x,
                    Err(_) => return None
                };

                let mut sizes = match attrs.get(atom!("sizes")) {
                    Some(s) => s.split('x').filter_map(|d| u32::from_str(d).ok()),
                    None => return None
                };

                let (x, y) = match (sizes.next(), sizes.next()) {
                    (Some(x), Some(y)) => (Some(x), Some(y)),
                    _ => return None
                };

                Some({
                    let mut icon = Icon::from_url(icon_url);
                    icon.width = x;
                    icon.height = y;
                    icon
                })
            })
            .collect()
    }
}

#[test]
fn test_default_favicon_paths() {
    use url;
    let mut x = IconScraper::from_url(
        url::Url::parse("http://example.com/a/b/c/d/e/f").unwrap()
    );
    let s = DefaultFaviconPathStrategy;
    let paths = s.get_uneducated_guesses(&mut x)
        .into_iter()
        .map(|u| u.url.serialize_path().unwrap())
        .collect::<Vec<String>>();

    assert_eq!(paths, vec![
        "/a/b/c/d/e/favicon.ico",
        "/a/b/c/d/favicon.ico",
        "/a/b/c/favicon.ico",
        "/a/b/favicon.ico",
        "/a/favicon.ico",
        "/favicon.ico",
    ]);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    let root = create_node(2);
    let left = add_left(&root, 3);
    add_left(&left, 8);
    add_right(&left, 13);
    let right = add_right(&root, 5);
    add_left(&right, 21);
    add_right(&right, 34);
    println!("{:?}", reverse_odd_levels(root)); // [2,5,3,8,13,21,34]

    let root = create_node(7);
    add_left(&root, 13);
    add_right(&root, 11);
    println!("{:?}", reverse_odd_levels(root)); // [7,11,13]
}
<commit_msg>Update problem 2415<commit_after>use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    fn to_tree(nodes: Vec<i32>) -> Option<Rc<RefCell<TreeNode>>> {
        let mut deque: VecDeque<Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
        let mut root: Option<Rc<RefCell<TreeNode>>> = None;
        deque.push_back(create_node(nodes[0]));
        let mut i = 1;
        while i < nodes.len() {
            let parent = deque.pop_front().unwrap();
            deque.push_back(add_left(&parent, nodes[i]));
            deque.push_back(add_right(&parent, nodes[i + 1]));
            i += 2;
            if root == None {
                root = parent;
            }
        }
        root
    }

    let root = to_tree(vec![2, 3, 5, 8, 13, 21, 34]);
    println!("{:?}", reverse_odd_levels(root)); // [2,5,3,8,13,21,34]

    let root = to_tree(vec![7, 13, 11]);
    println!("{:?}", reverse_odd_levels(root)); // [7,11,13]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,2,2,2,2,1,1,1,1]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 6, 7, 8, 9, 1, 2, 3, 4]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,4,3,2,1,9,8,7,6]
}
<|endoftext|>