<commit_before>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! seq_io::parallel::parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // `false` will stop the reader
//!         true
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Default + Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<P, O, W, F, Out>(mut reader: P, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where P: Reader,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut P::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<P::DataSet, P::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<Option<P::DataSet>>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(Some(r)) = empty_recv.recv() {
                            r
                        } else {
                            // 'ParallelRecordsets::stop()' called
                            return;
                        };

                    // each time, we need a new reference
                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(Some(P::DataSet::default())).unwrap();
        }

        let mut records = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: P::DataSet::default(),
        };

        let out = func(&mut records);

        records.stop();

        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<Option<R>>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
 {

    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b R, O), E>> {
        if let Some(result) = self.done_recv.recv().unwrap() {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(Some(prev_rset)).ok(); // error: channel closed is not a problem, happens after calling stop()
                    return Some(Ok((&self.current_recordset, o)));
                }
                Err(e) => return Some(Err(e))
            }
        } else {
            // 'done' signal received
            return None;
        }
    }

    // has to be called before object goes out of scope
    // currently, the signal is delayed (has to wait until it is popped from the
    // 'empty' queue)
    // TODO: should an AtomicBool be used?
    fn stop(self) {
        self.empty_send.send(None).ok();
    }
}

macro_rules! parallel_record_impl {
    ($name:ident, $rdr:ty, $record:ty, $io_r:tt, $err:ty) => {

        pub fn $name<$io_r, O, W, F>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<(), $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &O) -> bool,
        {
            let reader = ResultSetParser::new(parser);

            read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let mut out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&r.1) {
                        if ! func(x.0, x.1) {
                            break;
                        }
                    }
                }
                Ok(())
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, fasta::Reader<R>, fasta::RefRecord, R, fasta::ParseError);

parallel_record_impl!(parallel_fastq, fastq::Reader<R>, fastq::RefRecord, R, fastq::ParseError);

struct ResultSetParser<P, O>(P, PhantomData<O>);

impl<P, O> ResultSetParser<P, O> {
    pub fn new(p: P) -> ResultSetParser<P, O> {
        ResultSetParser(p, PhantomData)
    }
}

impl<P, O> Reader for ResultSetParser<P, O>
    where P: Reader,
          O: Default + Send {

    type DataSet = ResultSet<P::DataSet, O>;
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

struct ResultSet<R, O>(pub R, pub O) where R: Default + Send, O: Default + Send;

impl<R, O> Default for ResultSet<R, O>
    where R: Default + Send, O: Default + Send
{
    fn default() -> Self {
        ResultSet(R::default(), O::default())
    }
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<commit_msg>Refactor & simplify parallel_record_impl macro and make it public<commit_after>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! seq_io::parallel::parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // `false` will stop the reader
//!         true
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Default + Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<P, O, W, F, Out>(mut reader: P, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where P: Reader,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut P::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<P::DataSet, P::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<Option<P::DataSet>>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(Some(r)) = empty_recv.recv() {
                            r
                        } else {
                            // 'ParallelRecordsets::stop()' called
                            return;
                        };

                    // each time, we need a new reference
                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(Some(P::DataSet::default())).unwrap();
        }

        let mut records = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: P::DataSet::default(),
        };

        let out = func(&mut records);

        records.stop();

        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<Option<R>>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
 {

    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b R, O), E>> {
        if let Some(result) = self.done_recv.recv().unwrap() {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(Some(prev_rset)).ok(); // error: channel closed is not a problem, happens after calling stop()
                    return Some(Ok((&self.current_recordset, o)));
                }
                Err(e) => return Some(Err(e))
            }
        } else {
            // 'done' signal received
            return None;
        }
    }

    // has to be called before object goes out of scope
    // currently, the signal is delayed (has to wait until it is popped from the
    // 'empty' queue)
    // TODO: should an AtomicBool be used?
    fn stop(self) {
        self.empty_send.send(None).ok();
    }
}

#[macro_export]
macro_rules! parallel_record_impl {
    ($name:ident, $io_r:tt, $rdr:ty, $record:ty, $err:ty) => {

        pub fn $name<$io_r, O, W, F>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<(), $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &O) -> bool,
        {
            let reader = $crate::parallel::ReusableReader::new(parser);

            $crate::parallel::read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&r.1) {
                        if ! func(x.0, x.1) {
                            break;
                        }
                    }
                }
                Ok(())
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, R, fasta::Reader<R>, fasta::RefRecord, fasta::ParseError);

parallel_record_impl!(parallel_fastq, R, fastq::Reader<R>, fastq::RefRecord, fastq::ParseError);

pub struct ReusableReader<P, O>(P, PhantomData<O>);

impl<P, O> ReusableReader<P, O> {
    pub fn new(p: P) -> ReusableReader<P, O> {
        ReusableReader(p, PhantomData)
    }
}

impl<P, O> Reader for ReusableReader<P, O>
    where P: Reader,
          O: Default + Send {

    type DataSet = (P::DataSet, O);
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<|endoftext|>


<commit_before>use super::super::{Grid, Coord};
use super::*;

#[derive(Debug, Clone, Copy, PartialEq)]
enum EvCand {
    Ok,
    Elim(f64),
}

#[derive(Debug)]
enum Move {
    Decide(f64, usize, i32),
    Elim(f64, Vec<(usize, i32)>),
}

pub struct Evaluator {
    n_cells: usize,
    shape: FieldShape,
    val: Vec<i32>,
    clue: Vec<i32>,
    cand_score: Vec<[EvCand; (MAX_VAL + 1) as usize]>, // 1-origin for simplicity
    total_score: f64,
    inconsistent: bool,
    move_cand: Vec<Move>,
}

const UNIQUE_ELIMINATION: f64 = 0.8f64;
const SMALL_LARGE_ELIMINATION: f64 = 1.0f64;

impl Evaluator {
    pub fn new(problem: &Grid<Clue>) -> Evaluator {
        let n_cells = (problem.height() * problem.width()) as usize;

        let mut has_clue = Grid::new(problem.height(), problem.width(), false);
        for i in 0..n_cells {
            if let Clue::Clue { vertical: _, horizontal: _ } = problem[i] {
                has_clue[i] = true;
            }
        }
        let shape = FieldShape::new(&has_clue);
        let mut clue = vec![0; shape.group_to_cells.len()];
        for i in 0..shape.group_to_cells.len() {
            let clue_loc = shape.clue_locations[i];
            clue[i] = match clue_loc {
                ClueLocation::Horizontal(h) => match problem[h] {
                    Clue::Clue { horizontal: h, vertical: _ } => h,
                    _ => unreachable!(),
                },
                ClueLocation::Vertical(v) => match problem[v] {
                    Clue::Clue { horizontal: _, vertical: v } => v,
                    _ => unreachable!(),
                },
            }
        }
        Evaluator {
            n_cells: n_cells,
            shape: shape,
            val: vec![UNDECIDED; n_cells],
            clue: clue,
            cand_score: vec![[EvCand::Ok; (MAX_VAL + 1) as usize]; n_cells],
            total_score: 0.0f64,
            inconsistent: false,
            move_cand: vec![],
        }
    }
    pub fn evaluate(&mut self) -> Option<f64> {
        let mut n_undecided = 0;
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                n_undecided += 1;
            }
        }
        loop {
            self.move_cand.clear();

            // apply possible eliminations
            self.simple_elimination();
            self.unique_decision();
            self.unique_decision();
            self.two_cells_propagation();
            self.naked_pair();

            self.remove_unnecessary_move();

            if self.move_cand.len() == 0 {
                break;
            }

            let mut lowest_decision = (1e20f64, 0, 0);
            let mut lowest_elim = (1e20f64, vec![]);
            for mv in &self.move_cand {
                match mv {
                    &Move::Decide(score, loc, v) => if score < lowest_decision.0 {
                        lowest_decision = (score, loc, v);
                    },
                    &Move::Elim(score, ref elims) => if score < lowest_elim.0 {
                        lowest_elim = (score, elims.clone());
                    }
                }
            }
            if lowest_elim.0 < lowest_decision.0 * 11.0f64 {
                // use elim
                for (loc, v) in lowest_elim.1 {
                    self.cand_score[loc][v as usize] = EvCand::Elim(lowest_elim.0);
                }
            } else {
                // use lowest_decision
                let mut move_score = 0.0f64;
                for mv in &self.move_cand {
                    if let &Move::Decide(score, _, _) = mv {
                        move_score += score.powf(-2.0f64);
                    }
                }
                move_score = move_score.powf(-1.0 / 2.0f64);
                move_score *= (n_undecided as f64).powf(0.3);

                self.total_score += move_score;
                self.val[lowest_decision.1] = lowest_decision.2;
                n_undecided -= 1;
            }
        }
        if n_undecided == 0 {
            Some(self.total_score)
        } else {
            None
        }
    }
    fn remove_unnecessary_move(&mut self) {
        let mut new_cand = vec![];
        for m in &self.move_cand {
            match m {
                &Move::Decide(score, loc, v) =>
                    if self.val[loc] == UNDECIDED {
                        new_cand.push(Move::Decide(score, loc, v))
                    },
                &Move::Elim(score, ref elims) => {
                    let mut new_elims = vec![];
                    for &(loc, v) in elims {
                        let isok = match self.cand_score[loc][v as usize] {
                            EvCand::Ok => true,
                            EvCand::Elim(sc) => score < sc,
                        };
                        if isok {
                            new_elims.push((loc, v));
                        }
                    }
                    if new_elims.len() > 0 {
                        new_cand.push(Move::Elim(score, new_elims));
                    }
                },
            }
        }
        self.move_cand = new_cand;
    }
    fn simple_elimination(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] != UNDECIDED {
                    used_mask |= 1u32 << self.val[c];
                    rem_sum -= self.val[c];
                }
            }
            let rem_cells = self.shape.group_to_cells[gi].size() as i32 - used_mask.count_ones() as i32;
            if rem_cells == 0 {
                continue;
            }
            if rem_cells == 1 {
                let mut ep = 0;
                for c in self.shape.group_to_cells[gi] {
                    if self.val[c] == UNDECIDED {
                        ep = c;
                    }
                }
                self.move_cand.push(Move::Decide(4.0, ep, rem_sum));
                continue;
            }

            let mut allowed_cand = ((2u32 << MAX_VAL) - 2u32) ^ used_mask;
            let mut required = 0u32;
            // eliminate too large candidates
            {
                let mut sum_small = 0;
                let mut n_cand_checked = 0;
                let mut max_cand_checked = 0;
                let mut low_bits = 0;
                for i in 1..(MAX_VAL + 1) {
                    if (allowed_cand & (1u32 << i)) != 0 {
                        if n_cand_checked == rem_cells - 1 {
                            max_cand_checked = i;
                            break;
                        } else {
                            sum_small += i;
                            n_cand_checked += 1;
                            low_bits |= 1u32 << i;
                        }
                    }
                }
                let mut max_allowed = rem_sum - sum_small;

                if max_allowed < max_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if max_allowed < MAX_VAL {
                    if max_allowed == max_cand_checked + 1 {
                        allowed_cand &= !(1u32 << max_cand_checked);
                    }
                    allowed_cand &= (2u32 << max_allowed) - 2u32;
                }
                if max_allowed == max_cand_checked {
                    required |= low_bits | (1u32 << max_cand_checked);
                } else if max_allowed == max_cand_checked {
                    required |= low_bits | (1u32 << (max_cand_checked + 1));
                }
            }
            {
                let mut sum_large = 0;
                let mut n_cand_checked = 0;
                let mut min_cand_checked = 0;
                let mut high_bits = 0u32;
                for i in 1..(MAX_VAL + 1) {
                    let i = MAX_VAL + 1 - i;
                    if (allowed_cand & (1u32 << i)) != 0 {
                        if n_cand_checked == rem_cells - 1 {
                            min_cand_checked = i;
                            break;
                        } else {
                            sum_large += i;
                            n_cand_checked += 1;
                            high_bits |= 1u32 << i;
                        }
                    }
                }
                let mut min_allowed = rem_sum - sum_large;

                if min_allowed > min_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if min_allowed > 1 {
                    if min_allowed == min_cand_checked - 1 {
                        allowed_cand &= !(1u32 << min_cand_checked);
                    }
                    allowed_cand &= !((2u32 << (min_allowed - 1)) - 2u32);
                }
                if min_allowed == min_cand_checked {
                    required |= high_bits | (1u32 << min_cand_checked);
                } else if min_allowed == min_cand_checked - 1 {
                    required |= high_bits | (1u32 << (min_cand_checked - 1));
                }
            }

            let mut elims = vec![];
            for n in 1..(MAX_VAL + 1) {
                if (allowed_cand & (1u32 << n)) == 0 {
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            elims.push((c, n));
                        }
                    }
                }
            }
            self.move_cand.push(Move::Elim(SMALL_LARGE_ELIMINATION, elims));

            for n in 1..(MAX_VAL + 1) {
                if (required & (1u32 << n)) != 0 {
                    let mut cost = 0.0f64;
                    let mut pos = None;
                    let mut twice = false;
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            if let EvCand::Elim(s) = self.cand_score[c][n as usize] {
                                cost += s;
                            } else {
                                if pos == None {
                                    pos = Some(c);
                                } else {
                                    twice = true;
                                    break;
                                }
                            }
                        } else if self.val[c] == n {
                            twice = true;
                            break;
                        }
                    }
                    if !twice {
                        if let Some(c) = pos {
                            self.move_cand.push(Move::Decide(cost + 4.0, c, n));
                        } else {
                            self.inconsistent = true;
                            return;
                        }
                    }
                }
            }
        }
    }
    fn unique_elimination(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] && self.val[i] != UNDECIDED {
                let (g1, g2) = self.shape.cell_to_groups[i];
                let mut mv = vec![];
                for c in self.shape.group_to_cells[g1] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                for c in self.shape.group_to_cells[g2] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                self.move_cand.push(Move::Elim(UNIQUE_ELIMINATION, mv));
            }
        }
    }
    fn unique_decision(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                let mut cost = 0.0f64;
                let mut cand = -1;
                for v in 1..(MAX_VAL + 1) {
                    match self.cand_score[i][v as usize] {
                        EvCand::Ok => if cand == -1 {
                            cand = v;
                        } else {
                            cand = -2;
                        },
                        EvCand::Elim(c) => cost += c,
                    }
                }
                if cand == -1 {
                    self.inconsistent = true;
                    return;
                } else if cand != -2 {
                    self.move_cand.push(Move::Decide(cost, i, cand));
                }
            }
        }
    }
    fn two_cells_propagation(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            let mut undet1 = None;
            let mut undet2 = None;
            let mut more_than_two = false;
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] == UNDECIDED {
                    if undet1 == None {
                        undet1 = Some(c);
                    } else if undet2 == None {
                        undet2 = Some(c);
                    } else {
                        more_than_two = true;
                    }
                } else {
                    rem_sum -= self.val[c];
                }
            }
            if !more_than_two && undet2 != None {
                if let (Some(c1), Some(c2)) = (undet1, undet2) {
                    for n in 1..(MAX_VAL + 1) {
                        if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c2, n2)]));
                            }
                        }
                        if let EvCand::Elim(s) = self.cand_score[c2][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c1, n2)]));
                            }
                        }
                    }
                } else {
                    unreachable!();
                }
            }
        }
    }
    fn naked_pair(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut two_cand_cells = vec![];
            for c1 in self.shape.group_to_cells[gi] {
                let mut oks = 0u32;
                let mut score = 0.0f64;
                for n in 1..(MAX_VAL + 1) {
                    if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                        score += s;
                    } else {
                        oks |= 1u32 << n;
                    }
                }
                if oks.count_ones() == 2 {
                    two_cand_cells.push((c1, oks, score));
                }
            }
            for i in 0..two_cand_cells.len() {
                for j in (i + 1)..two_cand_cells.len() {
                    if two_cand_cells[i].1 == two_cand_cells[j].1 {
                        let mut elims = vec![];
                        let x = two_cand_cells[i].1.trailing_zeros() as i32;
                        let y = (two_cand_cells[i].1 ^ (1u32 << x)).trailing_zeros() as i32;
                        for c in self.shape.group_to_cells[gi] {
                            if two_cand_cells[i].0 != c && two_cand_cells[j].0 != c {
                                elims.push((c, x));
                                elims.push((c, y));
                            }
                        }
                        self.move_cand.push(Move::Elim(two_cand_cells[i].2 + two_cand_cells[j].2, elims));
                    }
                }
            }
        }
    }
}
<commit_msg>Kakuro: bug fix in Evaluator<commit_after>use super::super::{Grid, Coord};
use super::*;

#[derive(Debug, Clone, Copy, PartialEq)]
enum EvCand {
    Ok,
    Elim(f64),
}

#[derive(Debug)]
enum Move {
    Decide(f64, usize, i32),
    Elim(f64, Vec<(usize, i32)>),
}

pub struct Evaluator {
    n_cells: usize,
    shape: FieldShape,
    val: Vec<i32>,
    clue: Vec<i32>,
    cand_score: Vec<[EvCand; (MAX_VAL + 1) as usize]>, // 1-origin for simplicity
    total_score: f64,
    inconsistent: bool,
    move_cand: Vec<Move>,
}

const UNIQUE_ELIMINATION: f64 = 0.8f64;
const SMALL_LARGE_ELIMINATION: f64 = 1.0f64;

impl Evaluator {
    pub fn new(problem: &Grid<Clue>) -> Evaluator {
        let n_cells = (problem.height() * problem.width()) as usize;

        let mut has_clue = Grid::new(problem.height(), problem.width(), false);
        for i in 0..n_cells {
            if let Clue::Clue { vertical: _, horizontal: _ } = problem[i] {
                has_clue[i] = true;
            }
        }
        let shape = FieldShape::new(&has_clue);
        let mut clue = vec![0; shape.group_to_cells.len()];
        for i in 0..shape.group_to_cells.len() {
            let clue_loc = shape.clue_locations[i];
            clue[i] = match clue_loc {
                ClueLocation::Horizontal(h) => match problem[h] {
                    Clue::Clue { horizontal: h, vertical: _ } => h,
                    _ => unreachable!(),
                },
                ClueLocation::Vertical(v) => match problem[v] {
                    Clue::Clue { horizontal: _, vertical: v } => v,
                    _ => unreachable!(),
                },
            }
        }
        Evaluator {
            n_cells: n_cells,
            shape: shape,
            val: vec![UNDECIDED; n_cells],
            clue: clue,
            cand_score: vec![[EvCand::Ok; (MAX_VAL + 1) as usize]; n_cells],
            total_score: 0.0f64,
            inconsistent: false,
            move_cand: vec![],
        }
    }
    pub fn evaluate(&mut self) -> Option<f64> {
        let mut n_undecided = 0;
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                n_undecided += 1;
            }
        }
        loop {
            self.move_cand.clear();

            // apply possible eliminations
            self.simple_elimination();
            self.unique_decision();
            self.unique_elimination();
            self.two_cells_propagation();
            self.naked_pair();

            self.remove_unnecessary_move();

            if self.move_cand.len() == 0 {
                break;
            }

            let mut lowest_decision = (1e20f64, 0, 0);
            let mut lowest_elim = (1e20f64, vec![]);
            for mv in &self.move_cand {
                match mv {
                    &Move::Decide(score, loc, v) => if score < lowest_decision.0 {
                        lowest_decision = (score, loc, v);
                    },
                    &Move::Elim(score, ref elims) => if score < lowest_elim.0 {
                        lowest_elim = (score, elims.clone());
                    }
                }
            }
            if lowest_elim.0 < lowest_decision.0 * 11.0f64 {
                // use elim
                for (loc, v) in lowest_elim.1 {
                    self.cand_score[loc][v as usize] = EvCand::Elim(lowest_elim.0);
                }
            } else {
                // use lowest_decision
                let mut move_score = 0.0f64;
                for mv in &self.move_cand {
                    if let &Move::Decide(score, _, _) = mv {
                        move_score += score.powf(-2.0f64);
                    }
                }
                move_score = move_score.powf(-1.0 / 2.0f64);
                move_score *= (n_undecided as f64).powf(0.3);

                self.total_score += move_score;
                self.val[lowest_decision.1] = lowest_decision.2;
                n_undecided -= 1;
            }
        }
        if n_undecided == 0 {
            Some(self.total_score)
        } else {
            None
        }
    }
    fn remove_unnecessary_move(&mut self) {
        let mut new_cand = vec![];
        for m in &self.move_cand {
            match m {
                &Move::Decide(score, loc, v) =>
                    if self.val[loc] == UNDECIDED {
                        new_cand.push(Move::Decide(score, loc, v))
                    },
                &Move::Elim(score, ref elims) => {
                    let mut new_elims = vec![];
                    for &(loc, v) in elims {
                        let isok = match self.cand_score[loc][v as usize] {
                            EvCand::Ok => true,
                            EvCand::Elim(sc) => score < sc,
                        };
                        if isok {
                            new_elims.push((loc, v));
                        }
                    }
                    if new_elims.len() > 0 {
                        new_cand.push(Move::Elim(score, new_elims));
                    }
                },
            }
        }
        self.move_cand = new_cand;
    }
    fn simple_elimination(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] != UNDECIDED {
                    used_mask |= 1u32 << self.val[c];
                    rem_sum -= self.val[c];
                }
            }
            let rem_cells = self.shape.group_to_cells[gi].size() as i32 - used_mask.count_ones() as i32;
            if rem_cells == 0 {
                continue;
            }
            if rem_cells == 1 {
                let mut ep = 0;
                for c in self.shape.group_to_cells[gi] {
                    if self.val[c] == UNDECIDED {
                        ep = c;
                    }
                }
                self.move_cand.push(Move::Decide(4.0, ep, rem_sum));
                continue;
            }

            let mut allowed_cand = ((2u32 << MAX_VAL) - 2u32) ^ used_mask;
            let mut required = 0u32;
            // eliminate too large candidates
            {
                let mut sum_small = 0;
                let mut n_cand_checked = 0;
                let mut max_cand_checked = 0;
                let mut low_bits = 0;
                for i in 1..(MAX_VAL + 1) {
                    if (allowed_cand & (1u32 << i)) != 0 {
                        if n_cand_checked == rem_cells - 1 {
                            max_cand_checked = i;
                            break;
                        } else {
                            sum_small += i;
                            n_cand_checked += 1;
                            low_bits |= 1u32 << i;
                        }
                    }
                }
                let mut max_allowed = rem_sum - sum_small;

                if max_allowed < max_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if max_allowed < MAX_VAL {
                    if max_allowed == max_cand_checked + 1 {
                        allowed_cand &= !(1u32 << max_cand_checked);
                    }
                    allowed_cand &= (2u32 << max_allowed) - 2u32;
                }
                if max_allowed == max_cand_checked {
                    required |= low_bits | (1u32 << max_cand_checked);
                } else if max_allowed == max_cand_checked {
                    required |= low_bits | (1u32 << (max_cand_checked + 1));
                }
            }
            {
                let mut sum_large = 0;
                let mut n_cand_checked = 0;
                let mut min_cand_checked = 0;
                let mut high_bits = 0u32;
                for i in 1..(MAX_VAL + 1) {
                    let i = MAX_VAL + 1 - i;
                    if (allowed_cand & (1u32 << i)) != 0 {
                        if n_cand_checked == rem_cells - 1 {
                            min_cand_checked = i;
                            break;
                        } else {
                            sum_large += i;
                            n_cand_checked += 1;
                            high_bits |= 1u32 << i;
                        }
                    }
                }
                let mut min_allowed = rem_sum - sum_large;

                if min_allowed > min_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if min_allowed > 1 {
                    if min_allowed == min_cand_checked - 1 {
                        allowed_cand &= !(1u32 << min_cand_checked);
                    }
                    allowed_cand &= !((2u32 << (min_allowed - 1)) - 2u32);
                }
                if min_allowed == min_cand_checked {
                    required |= high_bits | (1u32 << min_cand_checked);
                } else if min_allowed == min_cand_checked - 1 {
                    required |= high_bits | (1u32 << (min_cand_checked - 1));
                }
            }

            let mut elims = vec![];
            for n in 1..(MAX_VAL + 1) {
                if (allowed_cand & (1u32 << n)) == 0 {
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            elims.push((c, n));
                        }
                    }
                }
            }
            self.move_cand.push(Move::Elim(SMALL_LARGE_ELIMINATION, elims));

            for n in 1..(MAX_VAL + 1) {
                if (required & (1u32 << n)) != 0 {
                    let mut cost = 0.0f64;
                    let mut pos = None;
                    let mut twice = false;
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            if let EvCand::Elim(s) = self.cand_score[c][n as usize] {
                                cost += s;
                            } else {
                                if pos == None {
                                    pos = Some(c);
                                } else {
                                    twice = true;
                                    break;
                                }
                            }
                        } else if self.val[c] == n {
                            twice = true;
                            break;
                        }
                    }
                    if !twice {
                        if let Some(c) = pos {
                            self.move_cand.push(Move::Decide(cost + 4.0, c, n));
                        } else {
                            self.inconsistent = true;
                            return;
                        }
                    }
                }
            }
        }
    }
    fn unique_elimination(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] && self.val[i] != UNDECIDED {
                let (g1, g2) = self.shape.cell_to_groups[i];
                let mut mv = vec![];
                for c in self.shape.group_to_cells[g1] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                for c in self.shape.group_to_cells[g2] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                self.move_cand.push(Move::Elim(UNIQUE_ELIMINATION, mv));
            }
        }
    }
    fn unique_decision(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                let mut cost = 0.0f64;
                let mut cand = -1;
                for v in 1..(MAX_VAL + 1) {
                    match self.cand_score[i][v as usize] {
                        EvCand::Ok => if cand == -1 {
                            cand = v;
                        } else {
                            cand = -2;
                        },
                        EvCand::Elim(c) => cost += c,
                    }
                }
                if cand == -1 {
                    self.inconsistent = true;
                    return;
                } else if cand != -2 {
                    self.move_cand.push(Move::Decide(cost, i, cand));
                }
            }
        }
    }
    fn two_cells_propagation(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            let mut undet1 = None;
            let mut undet2 = None;
            let mut more_than_two = false;
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] == UNDECIDED {
                    if undet1 == None {
                        undet1 = Some(c);
                    } else if undet2 == None {
                        undet2 = Some(c);
                    } else {
                        more_than_two = true;
                    }
                } else {
                    rem_sum -= self.val[c];
                }
            }
            if !more_than_two && undet2 != None {
                if let (Some(c1), Some(c2)) = (undet1, undet2) {
                    for n in 1..(MAX_VAL + 1) {
                        if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c2, n2)]));
                            }
                        }
                        if let EvCand::Elim(s) = self.cand_score[c2][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c1, n2)]));
                            }
                        }
                    }
                } else {
                    unreachable!();
                }
            }
        }
    }
    fn naked_pair(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut two_cand_cells = vec![];
            for c1 in self.shape.group_to_cells[gi] {
                let mut oks = 0u32;
                let mut score = 0.0f64;
                for n in 1..(MAX_VAL + 1) {
                    if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                        score += s;
                    } else {
                        oks |= 1u32 << n;
                    }
                }
                if oks.count_ones() == 2 {
                    two_cand_cells.push((c1, oks, score));
                }
            }
            for i in 0..two_cand_cells.len() {
                for j in (i + 1)..two_cand_cells.len() {
                    if two_cand_cells[i].1 == two_cand_cells[j].1 {
                        let mut elims = vec![];
                        let x = two_cand_cells[i].1.trailing_zeros() as i32;
                        let y = (two_cand_cells[i].1 ^ (1u32 << x)).trailing_zeros() as i32;
                        for c in self.shape.group_to_cells[gi] {
                            if two_cand_cells[i].0 != c && two_cand_cells[j].0 != c {
                                elims.push((c, x));
                                elims.push((c, y));
                            }
                        }
                        self.move_cand.push(Move::Elim(two_cand_cells[i].2 + two_cand_cells[j].2, elims));
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use math::{
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<commit_msg>Made `Rectangled` take `self` by value<commit_after>use math::{
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};
use internal::Rectangle;

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<|endoftext|>


<commit_before>use into_string::*;
use parser::*;
use std::iter;

/// Options for rendering Textile markup language.
pub struct RenderOptions {
    pub compress: bool,
    pub indent: u8,
}

impl Default for RenderOptions {
    fn default() -> RenderOptions {
        RenderOptions {
            compress: false,
            indent: 2,
        }
    }
}

/// Renders Textile string into HTML string with default options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render("h2. *Heading of level 2*");
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render<S: IntoString>(text: S) -> String {
    render_blocks(&parse(text.into_string()), &RenderOptions::default())
}

/// Renders Textile string into HTML string with specified options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render_with("h2. *Heading of level 2*", textile::RenderOptions::default());
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render_with<S: IntoString>(text: S, options: RenderOptions) -> String {
    render_blocks(&parse(text.into_string()), &options)
}

fn render_attributes(attributes: &[Attribute], options: &RenderOptions) -> String {
    if !attributes.is_empty() {
        let mut res = Vec::new();

        for attribute in attributes {
            let attr = match *attribute {
                Attribute::Align(ref align) => format!("align=\"{}\"", align),
                Attribute::Class(ref list) => format!("class=\"{}\"", list.join(" ")),
                Attribute::Id(ref id) => format!("id=\"{}\"", id),
                Attribute::Language(ref lang) => format!("lang=\"{}\"", lang),
                Attribute::Style(ref props) => {
                    let mut res = Vec::new();

                    for (key, value) in props {
                        if !options.compress {
                            res.push(format!("{}: {}", key, value))
                        } else {
                            res.push(format!("{}:{}", key, value))
                        }
                    }

                    if !options.compress {
                        format!("style=\"{}\"", res.join(";"))
                    } else {
                        format!("style=\"{}\"", res.join("; "))
                    }
                }
            };
            res.push(attr);
        }
        format!(" {}", res.join(" "))
    } else {
        String::default()
    }
}

fn render_blocks(elements: &[Block], options: &RenderOptions) -> String {
    let mut res = String::new();

    for (idx, element) in elements.iter().enumerate() {
        if idx > 0 && idx < elements.len() && !options.compress {
            res.push_str("\n");
        }
        res.push_str(&*render_block(element, options));
    }
    res
}

fn render_block(element: &Block, options: &RenderOptions) -> String {
    match *element {
        Block::BlockQuotation { ref attributes, ref cite, ref elements } => {
            let cite_attr = if !cite.is_empty() {
                format!(" cite=\"{}\"", cite)
            } else {
                "".to_string()
            };

            if !options.compress {
                let mut res = String::new();
                let spaces: String = iter::repeat(" ").take(options.indent as usize).collect();

                for element in elements {
                    res.push_str(&*format!("\n{}{}", spaces, render_block(element, options)));
                }
                format!("
{}\n
",
                        render_attributes(attributes, options),
                        cite_attr,
                        res)
            } else {
                format!("
{}
",
                        render_attributes(attributes, options),
                        cite_attr,
                        render_blocks(elements, options))
            }
        }
        Block::CodeBlock { ref attributes, ref code } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    code)
        }
        Block::Heading { ref attributes, level, ref elements } => {
            format!("<h{0}{1}>{2}</h{0}>",
                    level,
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        }
        Block::NoTextileBlock(ref strings) => strings.join("\n"),
        Block::Paragraph { ref attributes, ref elements, .. } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        },
        Block::Pre {ref attributes, ref lines} => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    lines.join("\n"))
        },
        _ => "".to_string(),
    }
}

fn render_inline_elements(elements: &[Inline], options: &RenderOptions) -> String {
    let mut res = String::new();

    for element in elements {
        let html = match *element {
            Inline::Abbreviation { ref abbr, ref transcript } => {
                format!("<acronym title=\"{}\">{}</acronym>",
                        transcript,
                        abbr)
            }
            Inline::Bold { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    BoldTagType::Strong => "strong",
                    BoldTagType::Bold => "b",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Break => "
".to_string(),
            Inline::Citation { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Code(ref text) => format!("{}", text),
            Inline::Image { ref attributes, ref alt, ref href, ref src } => {
                let img = if !alt.is_empty() {
                    format!("",
                            src,
                            alt,
                            render_attributes(attributes, options))
                } else {
                    format!("",
                            src,
                            render_attributes(attributes, options))
                };

                if !href.is_empty() {
                    format!("{}", href, img)
                } else {
                    img
                }
            }
            Inline::Italic { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    ItalicTagType::Emphasis => "em",
                    ItalicTagType::Italic => "i",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Link { ref attributes, ref elements, ref href, ref title } => {
                if !title.is_empty() {
                    format!("{}",
                            href,
                            title,
                            render_attributes(attributes, options),
                            render_inline_elements(elements, options))
                } else {
                    format!("{}",
                            href,
                            render_attributes(attributes, options),
                            render_inline_elements(elements, options))
                }
            }
            Inline::Span { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Strikethrough { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Subscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Superscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Text(ref text) => text.to_string(),
            Inline::Underlined { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
        };
        res.push_str(&html);
    }
    res
}
<commit_msg>Fix rendering 'style' attribute if 'compress' render option is 'false'<commit_after>use into_string::*;
use parser::*;
use std::iter;

/// Options for rendering Textile markup language.
pub struct RenderOptions {
    pub compress: bool,
    pub indent: u8,
}

impl Default for RenderOptions {
    fn default() -> RenderOptions {
        RenderOptions {
            compress: false,
            indent: 2,
        }
    }
}

/// Renders Textile string into HTML string with default options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render("h2. *Heading of level 2*");
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render<S: IntoString>(text: S) -> String {
    render_blocks(&parse(text.into_string()), &RenderOptions::default())
}

/// Renders Textile string into HTML string with specified options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render_with("h2. *Heading of level 2*", textile::RenderOptions::default());
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render_with<S: IntoString>(text: S, options: RenderOptions) -> String {
    render_blocks(&parse(text.into_string()), &options)
}

fn render_attributes(attributes: &[Attribute], options: &RenderOptions) -> String {
    if !attributes.is_empty() {
        let mut res = Vec::new();

        for attribute in attributes {
            let attr = match *attribute {
                Attribute::Align(ref align) => format!("align=\"{}\"", align),
                Attribute::Class(ref list) => format!("class=\"{}\"", list.join(" ")),
                Attribute::Id(ref id) => format!("id=\"{}\"", id),
                Attribute::Language(ref lang) => format!("lang=\"{}\"", lang),
                Attribute::Style(ref props) => {
                    let mut res = Vec::new();

                    for (key, value) in props {
                        if !options.compress {
                            res.push(format!("{}: {}", key, value))
                        } else {
                            res.push(format!("{}:{}", key, value))
                        }
                    }

                    if !options.compress {
                        format!("style=\"{}\"", res.join("; "))
                    } else {
                        format!("style=\"{}\"", res.join(";"))
                    }
                }
            };
            res.push(attr);
        }
        format!(" {}", res.join(" "))
    } else {
        String::default()
    }
}

fn render_blocks(elements: &[Block], options: &RenderOptions) -> String {
    let mut res = String::new();

    for (idx, element) in elements.iter().enumerate() {
        if idx > 0 && idx < elements.len() && !options.compress {
            res.push_str("\n");
        }
        res.push_str(&*render_block(element, options));
    }
    res
}

fn render_block(element: &Block, options: &RenderOptions) -> String {
    match *element {
        Block::BlockQuotation { ref attributes, ref cite, ref elements } => {
            let cite_attr = if !cite.is_empty() {
                format!(" cite=\"{}\"", cite)
            } else {
                "".to_string()
            };

            if !options.compress {
                let mut res = String::new();
                let spaces: String = iter::repeat(" ").take(options.indent as usize).collect();

                for element in elements {
                    res.push_str(&*format!("\n{}{}", spaces, render_block(element, options)));
                }
                format!("
{}\n
",
                        render_attributes(attributes, options),
                        cite_attr,
                        res)
            } else {
                format!("
{}
",
                        render_attributes(attributes, options),
                        cite_attr,
                        render_blocks(elements, options))
            }
        }
        Block::CodeBlock { ref attributes, ref code } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    code)
        }
        Block::Heading { ref attributes, level, ref elements } => {
            format!("<h{0}{1}>{2}</h{0}>",
                    level,
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        }
        Block::NoTextileBlock(ref strings) => strings.join("\n"),
        Block::Paragraph { ref attributes, ref elements, .. } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        },
        Block::Pre {ref attributes, ref lines} => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    lines.join("\n"))
        },
        _ => "".to_string(),
    }
}

fn render_inline_elements(elements: &[Inline], options: &RenderOptions) -> String {
    let mut res = String::new();

    for element in elements {
        let html = match *element {
            Inline::Abbreviation { ref abbr, ref transcript } => {
                format!("<acronym title=\"{}\">{}</acronym>",
                        transcript,
                        abbr)
            }
            Inline::Bold { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    BoldTagType::Strong => "strong",
                    BoldTagType::Bold => "b",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Break => "
".to_string(),
            Inline::Citation { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Code(ref text) => format!("{}", text),
            Inline::Image { ref attributes, ref alt, ref href, ref src } => {
                let img = if !alt.is_empty() {
                    format!("",
                            src,
                            alt,
                            render_attributes(attributes, options))
                } else {
                    format!("",
                            src,
                            render_attributes(attributes, options))
                };

                if !href.is_empty() {
                    format!("{}", href, img)
                } else {
                    img
                }
            }
            Inline::Italic { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    ItalicTagType::Emphasis => "em",
                    ItalicTagType::Italic => "i",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Link { ref attributes, ref elements, ref href, ref title } => {
                if !title.is_empty() {
                    format!("{}",
                            href,
                            title,
                            render_attributes(attributes, options),
                            render_inline_elements(elements, options))
                } else {
                    format!("{}",
                            href,
                            render_attributes(attributes, options),
                            render_inline_elements(elements, options))
                }
            }
            Inline::Span { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Strikethrough { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Subscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Superscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Text(ref text) => text.to_string(),
            Inline::Underlined { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
        };
        res.push_str(&html);
    }
    res
}
<|endoftext|>


<commit_before>/// Used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// When a value goes out of scope, it will have its `drop` method called if
/// its type implements `Drop`. Then, any fields the value contains will also
/// be dropped recursively.
///
/// Because of this recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
///
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
/// for some more elaboration.
///
/// [book]: ../../book/ch15-03-drop.html
///
/// # Examples
///
/// ## Implementing `Drop`
///
/// The `drop` method is called when `_x` goes out of scope, and therefore
/// `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping!");
///     }
/// }
///
/// fn main() {
///     let _x = HasDrop;
/// }
/// ```
///
/// ## Dropping is done recursively
///
/// When `outer` goes out of scope, the `drop` method will be called first for
/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and
/// then `Dropping Inner!`.
///
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
///     fn drop(&mut self) {
///         println!("Dropping Inner!");
///     }
/// }
///
/// impl Drop for Outer {
///     fn drop(&mut self) {
///         println!("Dropping Outer!");
///     }
/// }
///
/// fn main() {
///     let _x = Outer(Inner);
/// }
/// ```
///
/// ## Variables are dropped in reverse order of declaration
///
/// `_first` is declared first and `_second` is declared second, so `main` will
/// print `Declared second!` and then `Declared first!`.
///
/// ```
/// struct PrintOnDrop(&'static str);
///
/// impl Drop for PrintOnDrop {
///     fn drop(&mut self) {
///         println!("{}", self.0);
///     }
/// }
///
/// fn main() {
///     let _first = PrintOnDrop("Declared first!");
///     let _second = PrintOnDrop("Declared second!");
/// }
/// ```
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// Executes the destructor for this type.
    ///
    /// This method is called implicitly when the value goes out of scope,
    /// and cannot be called explicitly (this is compiler error [E0040]).
    /// However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// That only happens after the method is over.
    /// If this wasn't the case, `self` would be a dangling reference.
    ///
    /// # Panics
    ///
    /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`]
    /// in a `drop` implementation will likely abort.
    ///
    /// Note that even if this panics, the value is considered to be dropped;
    /// you must not cause `drop` to be called again. This is normally automatically
    /// handled by the compiler, but when using unsafe code, can sometimes occur
    /// unintentionally, particularly when using [`std::ptr::drop_in_place`].
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`panic!`]: ../macro.panic.html
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    /// [`std::ptr::drop_in_place`]: ../../std/ptr/fn.drop_in_place.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<commit_msg>rewrite Drop documentation<commit_after>/// Custom code within the destructor.
///
/// When a value is no longer needed, Rust will run a "destructor" on that value.
/// The most common way that a value is no longer needed is when it goes out of
/// scope. Destructors may still run in other circumstances, but we're going to
/// focus on scope for the examples here. To learn about some of those other cases,
/// please see [the reference] section on destructors.
///
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// This destructor consists of two components:
/// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type.
/// - The automatically generated "drop glue" which recursively calls the destructors
///     of the all fields of this value.
///
/// As Rust automatically calls the destructors of all contained fields,
/// you don't have to implement `Drop` in most cases. But there are some cases where
/// it is useful, for example for types which directly manage a resource.
/// That resource may be memory, it may be a file descriptor, it may be a network socket.
/// Once a value of that type is no longer going to be used, it should "clean up" its
/// resource by freeing the memory or closing the file or socket. This is
/// the job of a destructor, and therefore the job of `Drop::drop`.
///
/// ## Examples
///
/// To see destructors in action, let's take a look at the following program:
///
/// ```rust
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping HasDrop!");
///     }
/// }
///
/// struct HasTwoDrops {
///     one: HasDrop,
///     two: HasDrop,
/// }
///
/// impl Drop for HasTwoDrops {
///     fn drop(&mut self) {
///         println!("Dropping HasTwoDrops!");
///     }
/// }
///
/// fn main() {
///     let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
///     println!("Running!");
/// }
/// ```
///
/// Rust will first call `Drop::drop` for `_x` and then for both `_x.one` and `_x.two`,
/// meaning that running this will print
///
/// ```text
/// Running!
/// Dropping HasTwoDrops!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
///
/// Even if we remove the implementation of `Drop` for `HasTwoDrop`, the destructors of its fields are still called.
/// This would result in
///
/// ```test
/// Running!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
///
/// ## You cannot call `Drop::drop` yourself
///
/// Because `Drop::drop` is used to clean up a value, it may be dangerous to use this value after
/// the method has been called. As `Drop::drop` does not take ownership of its input,
/// Rust prevents misuse by not allowing you to call `Drop::drop` directly.
///
/// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error.
///
/// If you'd like explicitly call the destructor of a value, [`std::mem::drop`] can be used instead.
///
/// [`std::mem::drop`]: ../../std/mem/fn.drop.html
///
/// ## Drop order
///
/// Which of our two `HasDrop` drops first, though? For structs, it's the same
/// order that they're declared: first `one`, then `two`. If you'd like to try
/// this yourself, you can modify `HasDrop` above to contain some data, like an
/// integer, and then use it in the `println!` inside of `Drop`. This behavior is
/// guaranteed by the language.
///
/// Unlike for structs, local variables are dropped in reverse order:
///
/// ```rust
/// struct Foo;
///
/// impl Drop for Foo {
///     fn drop(&mut self) {
///         println!("Dropping Foo!")
///     }
/// }
///
/// struct Bar;
///
/// impl Drop for Bar {
///     fn drop(&mut self) {
///         println!("Dropping Bar!")
///     }
/// }
///
/// fn main() {
///     let _foo = Foo;
///     let _bar = Bar;
/// }
/// ```
///
/// This will print
///
/// ```text
/// Dropping Bar!
/// Dropping Foo!
/// ```
///
/// Please see [the reference] for the full rules.
///
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// ## `Copy` and `Drop` are exclusive
///
/// You cannot implement both [`Copy`] and `Drop` on the same type. Types that
/// are `Copy` get implicitly duplicated by the compiler, making it very
/// hard to predict when, and how often destructors will be executed. As such,
/// these types cannot have destructors.
///
/// [`Copy`]: ../../std/marker/trait.Copy.html
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// Executes the destructor for this type.
    ///
    /// This method is called implicitly when the value goes out of scope,
    /// and cannot be called explicitly (this is compiler error [E0040]).
    /// However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// That only happens after the method is over.
    /// If this wasn't the case, `self` would be a dangling reference.
    ///
    /// # Panics
    ///
    /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`]
    /// in a `drop` implementation will likely abort.
    ///
    /// Note that even if this panics, the value is considered to be dropped;
    /// you must not cause `drop` to be called again. This is normally automatically
    /// handled by the compiler, but when using unsafe code, can sometimes occur
    /// unintentionally, particularly when using [`std::ptr::drop_in_place`].
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`panic!`]: ../macro.panic.html
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    /// [`std::ptr::drop_in_place`]: ../../std/ptr/fn.drop_in_place.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<|endoftext|>