<commit_before>//! Handle network connections for a varlink service

use failure::Fail;
use {ErrorKind, Result};
//#![feature(getpid)]
//use std::process;
// FIXME
use libc;
use std::env;
use std::fs;
use std::io::{Read, Write};
use std::mem;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::{mpsc, Arc, Mutex, RwLock};
use std::thread;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixListener as AbstractUnixListener;

#[derive(Debug)]
enum VarlinkListener {
    TCP(Option<TcpListener>, bool),
    UNIX(Option<UnixListener>, bool),
}

#[derive(Debug)]
enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream),
}

impl<'a> VarlinkStream {
    pub fn split(&mut self) -> Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }
    pub fn shutdown(&mut self) -> Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both)?,
            VarlinkStream::UNIX(ref mut s) => s.shutdown(Shutdown::Both)?,
        }
        Ok(())
    }
}

fn activation_listener() -> Result<Option<i32>> {
    let nfds: u32;

    match env::var("LISTEN_FDS") {
        Ok(ref n) => match n.parse::<u32>() {
            Ok(n) if n >= 1 => nfds = n,
            _ => return Ok(None),
        },
        _ => return Ok(None),
    }

    unsafe {
        match env::var("LISTEN_PID") {
            //FIXME: replace Ok(getpid()) with Ok(process::id())
            Ok(ref pid) if pid.parse::<i32>() == Ok(libc::getpid()) => {}
            _ => return Ok(None),
        }
    }

    if nfds == 1 {
        return Ok(Some(3));
    }

    let fdnames: String;

    match env::var("LISTEN_FDNAMES") {
        Ok(n) => {
            fdnames = n;
        }
        _ => return Ok(None),
    }

    for (i, v) in fdnames.split(':').enumerate() {
        if v == "varlink" {
            return Ok(Some(3 + i as i32));
        }
    }

    Ok(None)
}

impl VarlinkListener {
    pub fn new<S: ?Sized + AsRef<str>>(address: &S) -> Result<Self> {
        let address = address.as_ref();
        if let Some(l) = activation_listener()? {
            if address.starts_with("tcp:") {
                unsafe {
                    return Ok(VarlinkListener::TCP(
                        Some(TcpListener::from_raw_fd(l)),
                        true,
                    ));
                }
            } else if address.starts_with("unix:") {
                unsafe {
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(l)),
                        true,
                    ));
                }
            } else {
                return Err(ErrorKind::InvalidAddress.into());
            }
        }

        if address.starts_with("tcp:") {
            Ok(VarlinkListener::TCP(
                Some(TcpListener::bind(&address[4..])?),
                false,
            ))
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(';').next().unwrap());
            if addr.starts_with('@') {
                addr = addr.replacen('@', "\0", 1);
                let l = AbstractUnixListener::bind(addr)?;
                unsafe {
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(l.into_raw_fd())),
                        false,
                    ));
                }
            }
            // ignore error on non-existant file
            let _ = fs::remove_file(&*addr);
            let l = UnixListener::bind(addr)?;
            unsafe {
                Ok(VarlinkListener::UNIX(
                    Some(UnixListener::from_raw_fd(l.into_raw_fd())),
                    false,
                ))
            }
        } else {
            Err(ErrorKind::InvalidAddress.into())
        }
    }

    pub fn accept(&self, timeout: u64) -> Result<VarlinkStream> {
        if timeout > 0 {
            let fd = match self {
                VarlinkListener::TCP(Some(l), _) => l.as_raw_fd(),
                VarlinkListener::UNIX(Some(l), _) => l.as_raw_fd(),
                _ => return Err(ErrorKind::ConnectionClosed.into()),
            };

            unsafe {
                let mut readfs: libc::fd_set = mem::uninitialized();
                loop {
                    libc::FD_ZERO(&mut readfs);
                    let mut writefds: libc::fd_set = mem::uninitialized();
                    libc::FD_ZERO(&mut writefds);
                    let mut errorfds: libc::fd_set = mem::uninitialized();
                    libc::FD_ZERO(&mut errorfds);
                    let mut timeout = libc::timeval {
                        tv_sec: timeout as libc::time_t,
                        tv_usec: 0,
                    };

                    libc::FD_SET(fd, &mut readfs);
                    let ret = libc::select(
                        fd + 1,
                        &mut readfs,
                        &mut writefds,
                        &mut errorfds,
                        &mut timeout,
                    );
                    if ret != libc::EINTR && ret != libc::EAGAIN {
                        break;
                    }
                }
                if !libc::FD_ISSET(fd, &mut readfs) {
                    return Err(ErrorKind::Timeout.into());
                }
            }
        }
        match self {
            &VarlinkListener::TCP(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::TCP(s))
            }
            VarlinkListener::UNIX(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::UNIX(s))
            }
            _ => Err(ErrorKind::ConnectionClosed.into()),
        }
    }
    pub fn set_nonblocking(&self, b: bool) -> Result<()> {
        match *self {
            VarlinkListener::TCP(Some(ref l), _) => l.set_nonblocking(b)?,
            VarlinkListener::UNIX(Some(ref l), _) => l.set_nonblocking(b)?,
            _ => Err(ErrorKind::ConnectionClosed)?,
        }
        Ok(())
    }
}

impl Drop for VarlinkListener {
    fn drop(&mut self) {
        match *self {
            VarlinkListener::UNIX(Some(ref listener), false) => {
                if let Ok(local_addr) = listener.local_addr() {
                    if let Some(path) = local_addr.as_pathname() {
                        let _ = fs::remove_file(path);
                    }
                }
            }
            VarlinkListener::UNIX(ref mut listener, true) => {
                if let Some(l) = listener.take() {
                    unsafe {
                        let s = UnixStream::from_raw_fd(l.into_raw_fd());
                        let _ = s.set_read_timeout(None);
                    }
                }
            }
            VarlinkListener::TCP(ref mut listener, true) => {
                if let Some(l) = listener.take() {
                    unsafe {
                        let s = TcpStream::from_raw_fd(l.into_raw_fd());
                        let _ = s.set_read_timeout(None);
                    }
                }
            }
            _ => {}
        }
    }
}

enum Message {
    NewJob(Job),
    Terminate,
}

struct ThreadPool {
    workers: Vec<Worker>,
    num_busy: Arc<RwLock<i64>>,
    sender: mpsc::Sender<Message>,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Job = Box<FnBox + Send + 'static>;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        let num_busy = Arc::new(RwLock::new(0 as i64));

        for _ in 0..size {
            workers.push(Worker::new(Arc::clone(&receiver), Arc::clone(&num_busy)));
        }

        ThreadPool {
            workers,
            sender,
            num_busy,
        }
    }

    pub fn execute<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);

        self.sender.send(Message::NewJob(job)).unwrap();
    }

    pub fn num_busy(&self) -> i64 {
        let num_busy = self.num_busy.read().unwrap();
        *num_busy
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        for worker in &mut self.workers {
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>, num_busy: Arc<RwLock<i64>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv().unwrap();

            match message {
                Message::NewJob(job) => {
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy += 1;
                    }
                    job.call_box();
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy -= 1;
                    }
                }
                Message::Terminate => {
                    break;
                }
            }
        });

        Worker {
            thread: Some(thread),
        }
    }
}

/// `listen` creates a server, with `num_worker` threads listening on `varlink_uri`.
///
/// If an `accept_timeout` != 0 is specified, this function returns after the specified
/// amount of seconds, if no new connection is made in that time frame. It still waits for
/// all pending connections to finish.
///
///# Examples
///
///```
/// extern crate failure;
/// extern crate varlink;
/// use failure::Fail;
///
/// let service = varlink::VarlinkService::new(
///     "org.varlink",
///     "test service",
///     "0.1",
///     "http://varlink.org",
///     vec![/* Your varlink interfaces go here */],
/// );
///
/// if let Err(e) = varlink::listen(service, "unix:/tmp/test_listen_timeout", 10, 1) {
///     if e.kind() != varlink::ErrorKind::Timeout {
///         panic!("Error listen: {:?}", e.cause());
///     }
/// }
///```
///# Note
/// You don't have to use this simple server. With the `VarlinkService::handle()` method you
/// can implement your own server model using whatever framework you prefer.
pub fn listen<S: ?Sized + AsRef<str>>(
    service: ::VarlinkService,
    address: &S,
    workers: usize,
    accept_timeout: u64,
) -> Result<()> {
    let service = Arc::new(service);
    let listener = VarlinkListener::new(address)?;
    listener.set_nonblocking(false)?;
    let pool = ThreadPool::new(workers);

    loop {
        let mut stream = match listener.accept(accept_timeout) {
            Err(e) => {
                if e.kind() == ErrorKind::Timeout {
                    if pool.num_busy() == 0 {
                        return Err(e);
                    }
                    continue;
                } else {
                    return Err(e);
                }
            }
            r => r?,
        };
        let service = service.clone();

        pool.execute(move || {
            let (mut r, mut w) = stream.split().expect("Could not split stream");

            if let Err(err) = service.handle(&mut r, &mut w) {
                if err.kind() != ErrorKind::ConnectionClosed {
                    eprintln!("Worker error: {}", err);
                    for cause in err.causes().skip(1) {
                        eprintln!("  caused by: {}", cause);
                    }
                }
                let _ = stream.shutdown();
            }
        });
    }
}
<commit_msg>spawn new worker threads, if all workers are busy<commit_after>//! Handle network connections for a varlink service

use failure::Fail;
use {ErrorKind, Result};
//#![feature(getpid)]
//use std::process;
// FIXME
use libc;
use std::env;
use std::fs;
use std::io::{Read, Write};
use std::mem;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::{mpsc, Arc, Mutex, RwLock};
use std::thread;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixListener as AbstractUnixListener;

#[derive(Debug)]
enum VarlinkListener {
    TCP(Option<TcpListener>, bool),
    UNIX(Option<UnixListener>, bool),
}

#[derive(Debug)]
enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream),
}

impl<'a> VarlinkStream {
    pub fn split(&mut self) -> Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }
    pub fn shutdown(&mut self) -> Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both)?,
            VarlinkStream::UNIX(ref mut s) => s.shutdown(Shutdown::Both)?,
        }
        Ok(())
    }
}

fn activation_listener() -> Result<Option<i32>> {
    let nfds: u32;

    match env::var("LISTEN_FDS") {
        Ok(ref n) => match n.parse::<u32>() {
            Ok(n) if n >= 1 => nfds = n,
            _ => return Ok(None),
        },
        _ => return Ok(None),
    }

    unsafe {
        match env::var("LISTEN_PID") {
            //FIXME: replace Ok(getpid()) with Ok(process::id())
            Ok(ref pid) if pid.parse::<i32>() == Ok(libc::getpid()) => {}
            _ => return Ok(None),
        }
    }

    if nfds == 1 {
        return Ok(Some(3));
    }

    let fdnames: String;

    match env::var("LISTEN_FDNAMES") {
        Ok(n) => {
            fdnames = n;
        }
        _ => return Ok(None),
    }

    for (i, v) in fdnames.split(':').enumerate() {
        if v == "varlink" {
            return Ok(Some(3 + i as i32));
        }
    }

    Ok(None)
}

impl VarlinkListener {
    pub fn new<S: ?Sized + AsRef<str>>(address: &S) -> Result<Self> {
        let address = address.as_ref();
        if let Some(l) = activation_listener()? {
            if address.starts_with("tcp:") {
                unsafe {
                    return Ok(VarlinkListener::TCP(
                        Some(TcpListener::from_raw_fd(l)),
                        true,
                    ));
                }
            } else if address.starts_with("unix:") {
                unsafe {
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(l)),
                        true,
                    ));
                }
            } else {
                return Err(ErrorKind::InvalidAddress.into());
            }
        }

        if address.starts_with("tcp:") {
            Ok(VarlinkListener::TCP(
                Some(TcpListener::bind(&address[4..])?),
                false,
            ))
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(';').next().unwrap());
            if addr.starts_with('@') {
                addr = addr.replacen('@', "\0", 1);
                let l = AbstractUnixListener::bind(addr)?;
                unsafe {
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(l.into_raw_fd())),
                        false,
                    ));
                }
            }
            // ignore error on non-existant file
            let _ = fs::remove_file(&*addr);
            let l = UnixListener::bind(addr)?;
            unsafe {
                Ok(VarlinkListener::UNIX(
                    Some(UnixListener::from_raw_fd(l.into_raw_fd())),
                    false,
                ))
            }
        } else {
            Err(ErrorKind::InvalidAddress.into())
        }
    }

    pub fn accept(&self, timeout: u64) -> Result<VarlinkStream> {
        if timeout > 0 {
            let fd = match self {
                VarlinkListener::TCP(Some(l), _) => l.as_raw_fd(),
                VarlinkListener::UNIX(Some(l), _) => l.as_raw_fd(),
                _ => return Err(ErrorKind::ConnectionClosed.into()),
            };

            unsafe {
                let mut readfs: libc::fd_set = mem::uninitialized();
                loop {
                    libc::FD_ZERO(&mut readfs);
                    let mut writefds: libc::fd_set = mem::uninitialized();
                    libc::FD_ZERO(&mut writefds);
                    let mut errorfds: libc::fd_set = mem::uninitialized();
                    libc::FD_ZERO(&mut errorfds);
                    let mut timeout = libc::timeval {
                        tv_sec: timeout as libc::time_t,
                        tv_usec: 0,
                    };

                    libc::FD_SET(fd, &mut readfs);
                    let ret = libc::select(
                        fd + 1,
                        &mut readfs,
                        &mut writefds,
                        &mut errorfds,
                        &mut timeout,
                    );
                    if ret != libc::EINTR && ret != libc::EAGAIN {
                        break;
                    }
                }
                if !libc::FD_ISSET(fd, &mut readfs) {
                    return Err(ErrorKind::Timeout.into());
                }
            }
        }
        match self {
            &VarlinkListener::TCP(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::TCP(s))
            }
            VarlinkListener::UNIX(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::UNIX(s))
            }
            _ => Err(ErrorKind::ConnectionClosed.into()),
        }
    }
    pub fn set_nonblocking(&self, b: bool) -> Result<()> {
        match *self {
            VarlinkListener::TCP(Some(ref l), _) => l.set_nonblocking(b)?,
            VarlinkListener::UNIX(Some(ref l), _) => l.set_nonblocking(b)?,
            _ => Err(ErrorKind::ConnectionClosed)?,
        }
        Ok(())
    }
}

impl Drop for VarlinkListener {
    fn drop(&mut self) {
        match *self {
            VarlinkListener::UNIX(Some(ref listener), false) => {
                if let Ok(local_addr) = listener.local_addr() {
                    if let Some(path) = local_addr.as_pathname() {
                        let _ = fs::remove_file(path);
                    }
                }
            }
            VarlinkListener::UNIX(ref mut listener, true) => {
                if let Some(l) = listener.take() {
                    unsafe {
                        let s = UnixStream::from_raw_fd(l.into_raw_fd());
                        let _ = s.set_read_timeout(None);
                    }
                }
            }
            VarlinkListener::TCP(ref mut listener, true) => {
                if let Some(l) = listener.take() {
                    unsafe {
                        let s = TcpStream::from_raw_fd(l.into_raw_fd());
                        let _ = s.set_read_timeout(None);
                    }
                }
            }
            _ => {}
        }
    }
}

enum Message {
    NewJob(Job),
    Terminate,
}

struct ThreadPool {
    workers: Vec<Worker>,
    num_busy: Arc<RwLock<usize>>,
    sender: mpsc::Sender<Message>,
    receiver: Arc<Mutex<mpsc::Receiver<Message>>>,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Job = Box<FnBox + Send + 'static>;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        let num_busy = Arc::new(RwLock::new(0 as usize));

        for _ in 0..size {
            workers.push(Worker::new(Arc::clone(&receiver), Arc::clone(&num_busy)));
        }

        ThreadPool {
            workers,
            sender,
            receiver,
            num_busy,
        }
    }

    pub fn execute<F>(&mut self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);
        self.sender.send(Message::NewJob(job)).unwrap();
        if (self.num_busy() + 1) >= self.workers.len() {
            self.workers.push(Worker::new(
                Arc::clone(&self.receiver),
                Arc::clone(&self.num_busy),
            ));
        }
    }

    pub fn num_busy(&self) -> usize {
        let num_busy = self.num_busy.read().unwrap();
        *num_busy
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        for worker in &mut self.workers {
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>, num_busy: Arc<RwLock<usize>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv().unwrap();

            match message {
                Message::NewJob(job) => {
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy += 1;
                    }
                    job.call_box();
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy -= 1;
                    }
                }
                Message::Terminate => {
                    break;
                }
            }
        });

        Worker {
            thread: Some(thread),
        }
    }
}

/// `listen` creates a server, with `num_worker` threads listening on `varlink_uri`.
///
/// If an `accept_timeout` != 0 is specified, this function returns after the specified
/// amount of seconds, if no new connection is made in that time frame. It still waits for
/// all pending connections to finish.
///
///# Examples
///
///```
/// extern crate failure;
/// extern crate varlink;
/// use failure::Fail;
///
/// let service = varlink::VarlinkService::new(
///     "org.varlink",
///     "test service",
///     "0.1",
///     "http://varlink.org",
///     vec![/* Your varlink interfaces go here */],
/// );
///
/// if let Err(e) = varlink::listen(service, "unix:/tmp/test_listen_timeout", 10, 1) {
///     if e.kind() != varlink::ErrorKind::Timeout {
///         panic!("Error listen: {:?}", e.cause());
///     }
/// }
///```
///# Note
/// You don't have to use this simple server. With the `VarlinkService::handle()` method you
/// can implement your own server model using whatever framework you prefer.
pub fn listen<S: ?Sized + AsRef<str>>(
    service: ::VarlinkService,
    address: &S,
    initial_worker_threads: usize,
    accept_timeout: u64,
) -> Result<()> {
    let service = Arc::new(service);
    let listener = VarlinkListener::new(address)?;
    listener.set_nonblocking(false)?;
    let mut pool = ThreadPool::new(initial_worker_threads);

    loop {
        let mut stream = match listener.accept(accept_timeout) {
            Err(e) => {
                if e.kind() == ErrorKind::Timeout {
                    if pool.num_busy() == 0 {
                        return Err(e);
                    }
                    continue;
                } else {
                    return Err(e);
                }
            }
            r => r?,
        };
        let service = service.clone();

        pool.execute(move || {
            let (mut r, mut w) = stream.split().expect("Could not split stream");

            if let Err(err) = service.handle(&mut r, &mut w) {
                if err.kind() != ErrorKind::ConnectionClosed {
                    eprintln!("Worker error: {}", err);
                    for cause in err.causes().skip(1) {
                        eprintln!("  caused by: {}", cause);
                    }
                }
                let _ = stream.shutdown();
            }
        });
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<commit_msg>Update problem 174<commit_after>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 3
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![-5, -10, 1], vec![10, 30, 5]])
    ); // 1
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<|endoftext|>


<commit_before>/** Creates CSS boxes from a DOM. */
use au = gfx::geometry;
use core::dvec::DVec;
use css::styles::{SpecifiedStyle, empty_style_for_node_kind};
use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
use css::values::{Inherit, Initial, Specified};
use dom::element::*;
use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree, LayoutData};
use image::holder::ImageHolder;
use layout::box::*;
use layout::block::BlockFlowData;
use layout::context::LayoutContext;
use layout::flow::*;
use layout::inline::InlineFlowData;
use layout::root::RootFlowData;
use option::is_none;
use util::tree;

export LayoutTreeBuilder;

struct LayoutTreeBuilder {
    mut root_flow: Option<@FlowContext>,
    mut next_bid: int,
    mut next_cid: int
}

fn LayoutTreeBuilder() -> LayoutTreeBuilder {
    LayoutTreeBuilder {
        root_flow: None,
        next_bid: -1,
        next_cid: -1
    }
}

type BuilderContext = { flow: @FlowContext, consumer: BoxConsumer };

impl LayoutTreeBuilder {
    /* Debug-only ids */
    fn next_box_id() -> int { self.next_bid += 1; self.next_bid }
    fn next_flow_id() -> int { self.next_cid += 1; self.next_cid }

    /** Creates necessary box(es) and flow context(s) for the current DOM node,
    and recurses on its children. */
    fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: &BuilderContext) {
        let style = cur_node.style();
        // DEBUG
        debug!("Considering node: %?", fmt!("%?", cur_node.read(|n| copy n.kind )));

        // TODO: remove this once UA styles work
        // TODO: handle interactions with 'float', 'position' (CSS 2.1, Section 9.7)
        let simulated_display = match self.simulate_UA_display_rules(cur_node, &style) {
            DisplayNone => return, // tree ends here if 'display: none'
            v => v
        };

        // first, determine the box type, based on node characteristics
        let box_type = self.decide_box_type(cur_node, simulated_display);

        // then, figure out its proper context, possibly reorganizing.
        let next_flow: @FlowContext = match box_type {
            /* Text box is always an inline flow. create implicit inline
            flow if we aren't inside one already. */
            RenderBox_Text => {
                if (parent_ctx.flow.starts_inline_flow()) {
                    parent_ctx.flow
                } else {
                    self.make_flow(Flow_Inline)
                }
            },
            RenderBox_Image | RenderBox_Generic => {
                match simulated_display {
                    DisplayInline | DisplayInlineBlock => {
                        /* if inline, try to put into inline context,
                        making a new one if necessary */
                        if (parent_ctx.flow.starts_inline_flow()) {
                            parent_ctx.flow
                        } else {
                            self.make_flow(Flow_Inline)
                        }
                    },
                    /* block boxes always create a new context */
                    DisplayBlock => {
                        self.make_flow(Flow_Block)
                    },
                    _ => fail fmt!("unsupported display type in box generation: %?", simulated_display)
                }
            }
        };

        let builder_ctx : BuilderContext;

        // if this is a new flow, attach to parent flow and make a new BuilderContext.
        if !core::box::ptr_eq(next_flow, parent_ctx.flow) {
            debug!("LayoutTreeBuilder: using parent builder context");
            debug!("LayoutTreeBuilder: Adding child flow f%? of f%?",
                   parent_ctx.flow.d().id, next_flow.d().id);
            FlowTree.add_child(parent_ctx.flow, next_flow);

            builder_ctx = { flow: next_flow, consumer: BoxConsumer(next_flow) };
        } else {
            debug!("LayoutTreeBuilder: creating fresh builder context");
            builder_ctx = copy *parent_ctx;
        }

        // store reference to the flow context which contains any
        // boxes that correspond to cur_node. These boxes may
        // eventually be elided or split, but the mapping between
        // nodes and FlowContexts should not change during layout.
        assert cur_node.has_aux();
        do cur_node.aux |data| { data.flow = Some(builder_ctx.flow) }

        let new_box = self.make_box(layout_ctx, box_type, cur_node, builder_ctx.flow);
        debug!("LayoutTreeBuilder: Assign ^box to flow f%d", builder_ctx.flow.d().id);
        builder_ctx.consumer.push_box(layout_ctx, new_box);

        // recurse on child nodes.
        do NodeTree.each_child(&cur_node) |child_node| {
            self.construct_recursively(layout_ctx, *child_node, &builder_ctx); true
        }

        builder_ctx.consumer.pop_box(layout_ctx, new_box);

        // Fixup any irregularities, such as split inlines (CSS 2.1 Section 9.2.1.1)
        if (builder_ctx.flow.starts_inline_flow()) {
            let mut found_child_inline = false;
            let mut found_child_block = false;

            do FlowTree.each_child(builder_ctx.flow) |child_ctx| {
                match *child_ctx {
                    InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
                    BlockFlow(*) => found_child_block = true,
                    _ => {}
                }; true
            }

            if found_child_block && found_child_inline {
                self.fixup_split_inline(builder_ctx.flow)
            }
        }
    }

    fn fixup_split_inline(_foo: @FlowContext) {
        // TODO: finish me.
        fail ~"TODO: handle case where an inline is split by a block"
    }

    priv fn simulate_UA_display_rules(node: Node, style: &SpecifiedStyle) -> CSSDisplay {
        let resolved = match style.display_type {
            Inherit | Initial => DisplayInline, // TODO: remove once resolve works
            Specified(v) => v
        };

        if (resolved == DisplayNone) { return resolved; }

        do node.read |n| {
            match n.kind {
                ~Doctype(*) | ~Comment(*) => DisplayNone,
                ~Text(*) => DisplayInline,
                ~Element(e) => match e.kind {
                    ~HTMLHeadElement(*) => DisplayNone,
                    ~HTMLScriptElement(*) => DisplayNone,
                    ~HTMLParagraphElement(*) => DisplayBlock,
                    ~HTMLDivElement(*) => DisplayBlock,
                    ~HTMLBodyElement(*) => DisplayBlock,
                    ~HTMLHeadingElement(*) => DisplayBlock,
                    ~HTMLHtmlElement(*) => DisplayBlock,
                    ~HTMLUListElement(*) => DisplayBlock,
                    ~HTMLOListElement(*) => DisplayBlock,
                    _ => resolved
                }
            }
        }
    }

    /** entry point for box creation. Should only be
    called on root DOM element. */
    fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@FlowContext, ()> {
        let new_flow = self.make_flow(Flow_Root);
        self.root_flow = Some(new_flow);
        let builder_ctx = { flow: new_flow, consumer: BoxConsumer(new_flow) };
        self.construct_recursively(layout_ctx, root, &builder_ctx);
        return Ok(new_flow)
    }

    fn make_flow(ty : FlowContextType) -> @FlowContext {
        let data = FlowData(self.next_flow_id());
        let ret = match ty {
            Flow_Absolute    => @AbsoluteFlow(data),
            Flow_Block       => @BlockFlow(data, BlockFlowData()),
            Flow_Float       => @FloatFlow(data),
            Flow_InlineBlock => @InlineBlockFlow(data),
            Flow_Inline      => @InlineFlow(data, InlineFlowData()),
            Flow_Root        => @RootFlow(data, RootFlowData()),
            Flow_Table       => @TableFlow(data)
        };
        debug!("LayoutTreeBuilder: created flow: %s", ret.debug_str());
        ret
    }

    /**
       disambiguate between different methods here instead of inlining, since each
       case has very different complexity
    */
    fn make_box(layout_ctx: &LayoutContext, ty: RenderBoxType, node: Node, ctx: @FlowContext) -> @RenderBox {
        let ret = match ty {
            RenderBox_Generic => self.make_generic_box(layout_ctx, node, ctx),
            RenderBox_Text    => self.make_text_box(layout_ctx, node, ctx),
            RenderBox_Image   => self.make_image_box(layout_ctx, node, ctx),
        };
        debug!("LayoutTreeBuilder: created box: %s", ret.debug_str());
        ret
    }

    fn make_generic_box(_layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        @GenericBox(RenderBoxData(node, ctx, self.next_box_id()))
    }

    fn make_image_box(layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        do node.read |n| {
            match n.kind {
                ~Element(ed) => match ed.kind {
                    ~HTMLImageElement(d) => {
                        // TODO: this could be written as a pattern guard, but it triggers
                        // an ICE (mozilla/rust issue #3601)
                        if d.image.is_some() {
                            let holder = ImageHolder({copy *d.image.get_ref()},
                                                     layout_ctx.image_cache);

                            @ImageBox(RenderBoxData(node, ctx, self.next_box_id()), holder)
                        } else {
                            info!("Tried to make image box, but couldn't find image. Made generic box instead.");
                            self.make_generic_box(layout_ctx, node, ctx)
                        }
                    },
                    _ => fail ~"WAT error: why couldn't we make an image box?"
                },
                _ => fail ~"WAT error: why couldn't we make an image box?"
            }
        }

    }

    fn make_text_box(_layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        do node.read |n| {
            match n.kind {
                ~Text(string) => @UnscannedTextBox(RenderBoxData(node, ctx, self.next_box_id()), copy string),
                _ => fail ~"WAT error: why couldn't we make a text box?"
            }
        }
    }

    fn decide_box_type(node: Node, display: CSSDisplay) -> RenderBoxType {
        do node.read |n| {
            match n.kind {
                ~Doctype(*) | ~Comment(*) => fail ~"Hey, doctypes and comments shouldn't get here! They are display:none!",
                ~Text(*) => RenderBox_Text,
                ~Element(element) => {
                    // FIXME: Bad copy
                    match (copy element.kind, display) {
                        (~HTMLImageElement(d), _) if d.image.is_some() => RenderBox_Image,
//                      (_, Specified(_)) => GenericBox,
                        (_, _) => RenderBox_Generic // TODO: replace this with the commented lines
//                      (_, _) => fail ~"Can't create box for Node with non-specified 'display' type"
                    }
                }
            }
        }
    }
}
<commit_msg>Extract the flow simplication code that is run after a flow's children are built; add a new case that prunes whitespace-only inline flows that are first/last children of block flows.<commit_after>/** Creates CSS boxes from a DOM. */
use au = gfx::geometry;
use core::dvec::DVec;
use css::styles::{SpecifiedStyle, empty_style_for_node_kind};
use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
use css::values::{Inherit, Initial, Specified};
use dom::element::*;
use dom::node::{Comment, Doctype, Element, Text, Node, LayoutData};
use image::holder::ImageHolder;
use layout::box::*;
use layout::block::BlockFlowData;
use layout::context::LayoutContext;
use layout::flow::*;
use layout::inline::InlineFlowData;
use layout::root::RootFlowData;
use option::is_none;
use util::tree;

export LayoutTreeBuilder;

struct LayoutTreeBuilder {
    mut root_flow: Option<@FlowContext>,
    mut next_bid: int,
    mut next_cid: int
}

fn LayoutTreeBuilder() -> LayoutTreeBuilder {
    LayoutTreeBuilder {
        root_flow: None,
        next_bid: -1,
        next_cid: -1
    }
}

type BuilderContext = { flow: @FlowContext, consumer: BoxConsumer };

impl LayoutTreeBuilder {
    /* Debug-only ids */
    fn next_box_id() -> int { self.next_bid += 1; self.next_bid }
    fn next_flow_id() -> int { self.next_cid += 1; self.next_cid }

    /** Creates necessary box(es) and flow context(s) for the current DOM node,
    and recurses on its children. */
    fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: &BuilderContext) {
        let style = cur_node.style();
        // DEBUG
        debug!("Considering node: %?", fmt!("%?", cur_node.read(|n| copy n.kind )));

        // TODO: remove this once UA styles work
        // TODO: handle interactions with 'float', 'position' (CSS 2.1, Section 9.7)
        let simulated_display = match self.simulate_UA_display_rules(cur_node, &style) {
            DisplayNone => return, // tree ends here if 'display: none'
            v => v
        };

        // first, determine the box type, based on node characteristics
        let box_type = self.decide_box_type(cur_node, simulated_display);

        // then, figure out its proper context, possibly reorganizing.
        let next_flow: @FlowContext = match box_type {
            /* Text box is always an inline flow. create implicit inline
            flow if we aren't inside one already. */
            RenderBox_Text => {
                if (parent_ctx.flow.starts_inline_flow()) {
                    parent_ctx.flow
                } else {
                    self.make_flow(Flow_Inline)
                }
            },
            RenderBox_Image | RenderBox_Generic => {
                match simulated_display {
                    DisplayInline | DisplayInlineBlock => {
                        /* if inline, try to put into inline context,
                        making a new one if necessary */
                        if (parent_ctx.flow.starts_inline_flow()) {
                            parent_ctx.flow
                        } else {
                            self.make_flow(Flow_Inline)
                        }
                    },
                    /* block boxes always create a new context */
                    DisplayBlock => {
                        self.make_flow(Flow_Block)
                    },
                    _ => fail fmt!("unsupported display type in box generation: %?", simulated_display)
                }
            }
        };

        let builder_ctx : BuilderContext;

        // if this is a new flow, attach to parent flow and make a new BuilderContext.
        if !core::box::ptr_eq(next_flow, parent_ctx.flow) {
            debug!("LayoutTreeBuilder: using parent builder context");
            debug!("LayoutTreeBuilder: Adding child flow f%? of f%?",
                   parent_ctx.flow.d().id, next_flow.d().id);
            tree::add_child(&FlowTree, parent_ctx.flow, next_flow);

            builder_ctx = { flow: next_flow, consumer: BoxConsumer(next_flow) };
        } else {
            debug!("LayoutTreeBuilder: creating fresh builder context");
            builder_ctx = copy *parent_ctx;
        }

        // store reference to the flow context which contains any
        // boxes that correspond to cur_node. These boxes may
        // eventually be elided or split, but the mapping between
        // nodes and FlowContexts should not change during layout.
        assert cur_node.has_aux();
        do cur_node.aux |data| { data.flow = Some(builder_ctx.flow) }

        let new_box = self.make_box(layout_ctx, box_type, cur_node, builder_ctx.flow);
        debug!("LayoutTreeBuilder: Assign ^box to flow f%d", builder_ctx.flow.d().id);
        builder_ctx.consumer.push_box(layout_ctx, new_box);

        // recurse on child nodes.
        for tree::each_child(&NodeTree, &cur_node) |child_node| {
            self.construct_recursively(layout_ctx, *child_node, &builder_ctx);
        }

        builder_ctx.consumer.pop_box(layout_ctx, new_box);
        self.simplify_children_of_flow(layout_ctx, &builder_ctx);
    }

    // Fixup any irregularities such as:
    //
    // * split inlines (CSS 2.1 Section 9.2.1.1)
    // * elide non-preformatted whitespace-only text boxes and their
    //   flows (CSS 2.1 Section 9.2.2.1).
    //
    // The latter can only be done immediately adjacent to, or at the
    // beginning or end of a block flow. Otherwise, the whitespace
    // might affect whitespace collapsing with adjacent text.
    fn simplify_children_of_flow(_layout_ctx: &LayoutContext, builder_ctx: &BuilderContext) {
        match *builder_ctx.flow {
            InlineFlow(*) => {
                let mut found_child_inline = false;
                let mut found_child_block = false;

                for tree::each_child(&FlowTree, &builder_ctx.flow) |child_ctx: &@FlowContext| {
                    match **child_ctx {
                        InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
                        BlockFlow(*) => found_child_block = true,
                        _ => {}
                    }
                }

                if found_child_block && found_child_inline {
                    self.fixup_split_inline(builder_ctx.flow)
                }
            },
            BlockFlow(*) => {
                // FIXME: this will create refcounted cycles between the removed flow and any
                // of its RenderBox or FlowContext children, and possibly keep alive other junk
                let parent_flow = builder_ctx.flow;
                // check first/last child for whitespace-ness
                do tree::first_child(&FlowTree, &parent_flow).iter |first_flow: &@FlowContext| {
                    if first_flow.starts_inline_flow() {
                        let boxes = &first_flow.inline().boxes;
                        if boxes.len() == 1 && boxes[0].is_whitespace_only() {
                            debug!("LayoutTreeBuilder: pruning whitespace-only first child flow f%d from parent f%d",
                                   first_flow.d().id, parent_flow.d().id);
                            tree::remove_child(&FlowTree, parent_flow, *first_flow);
                        }
                    }
                }
                do tree::last_child(&FlowTree, &parent_flow).iter |last_flow: &@FlowContext| {
                    if last_flow.starts_inline_flow() {
                        let boxes = &last_flow.inline().boxes;
                        if boxes.len() == 1 && boxes.last().is_whitespace_only() {
                            debug!("LayoutTreeBuilder: pruning whitespace-only last child flow f%d from parent f%d",
                                   last_flow.d().id, parent_flow.d().id);
                            tree::remove_child(&FlowTree, parent_flow, *last_flow);
                        }
                    }
                }
            },
            _ => {}
        }
    }

    fn fixup_split_inline(_foo: @FlowContext) {
        // TODO: finish me.
        fail ~"TODO: handle case where an inline is split by a block"
    }

    priv fn simulate_UA_display_rules(node: Node, style: &SpecifiedStyle) -> CSSDisplay {
        let resolved = match style.display_type {
            Inherit | Initial => DisplayInline, // TODO: remove once resolve works
            Specified(v) => v
        };

        if (resolved == DisplayNone) { return resolved; }

        do node.read |n| {
            match n.kind {
                ~Doctype(*) | ~Comment(*) => DisplayNone,
                ~Text(*) => DisplayInline,
                ~Element(e) => match e.kind {
                    ~HTMLHeadElement(*) => DisplayNone,
                    ~HTMLScriptElement(*) => DisplayNone,
                    ~HTMLParagraphElement(*) => DisplayBlock,
                    ~HTMLDivElement(*) => DisplayBlock,
                    ~HTMLBodyElement(*) => DisplayBlock,
                    ~HTMLHeadingElement(*) => DisplayBlock,
                    ~HTMLHtmlElement(*) => DisplayBlock,
                    ~HTMLUListElement(*) => DisplayBlock,
                    ~HTMLOListElement(*) => DisplayBlock,
                    _ => resolved
                }
            }
        }
    }

    /** entry point for box creation. Should only be
    called on root DOM element. */
    fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@FlowContext, ()> {
        let new_flow = self.make_flow(Flow_Root);
        self.root_flow = Some(new_flow);
        let builder_ctx = { flow: new_flow, consumer: BoxConsumer(new_flow) };
        self.construct_recursively(layout_ctx, root, &builder_ctx);
        return Ok(new_flow)
    }

    fn make_flow(ty : FlowContextType) -> @FlowContext {
        let data = FlowData(self.next_flow_id());
        let ret = match ty {
            Flow_Absolute    => @AbsoluteFlow(data),
            Flow_Block       => @BlockFlow(data, BlockFlowData()),
            Flow_Float       => @FloatFlow(data),
            Flow_InlineBlock => @InlineBlockFlow(data),
            Flow_Inline      => @InlineFlow(data, InlineFlowData()),
            Flow_Root        => @RootFlow(data, RootFlowData()),
            Flow_Table       => @TableFlow(data)
        };
        debug!("LayoutTreeBuilder: created flow: %s", ret.debug_str());
        ret
    }

    /**
       disambiguate between different methods here instead of inlining, since each
       case has very different complexity
    */
    fn make_box(layout_ctx: &LayoutContext, ty: RenderBoxType, node: Node, ctx: @FlowContext) -> @RenderBox {
        let ret = match ty {
            RenderBox_Generic => self.make_generic_box(layout_ctx, node, ctx),
            RenderBox_Text    => self.make_text_box(layout_ctx, node, ctx),
            RenderBox_Image   => self.make_image_box(layout_ctx, node, ctx),
        };
        debug!("LayoutTreeBuilder: created box: %s", ret.debug_str());
        ret
    }

    fn make_generic_box(_layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        @GenericBox(RenderBoxData(node, ctx, self.next_box_id()))
    }

    fn make_image_box(layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        do node.read |n| {
            match n.kind {
                ~Element(ed) => match ed.kind {
                    ~HTMLImageElement(d) => {
                        // TODO: this could be written as a pattern guard, but it triggers
                        // an ICE (mozilla/rust issue #3601)
                        if d.image.is_some() {
                            let holder = ImageHolder({copy *d.image.get_ref()},
                                                     layout_ctx.image_cache);

                            @ImageBox(RenderBoxData(node, ctx, self.next_box_id()), holder)
                        } else {
                            info!("Tried to make image box, but couldn't find image. Made generic box instead.");
                            self.make_generic_box(layout_ctx, node, ctx)
                        }
                    },
                    _ => fail ~"WAT error: why couldn't we make an image box?"
                },
                _ => fail ~"WAT error: why couldn't we make an image box?"
            }
        }

    }

    fn make_text_box(_layout_ctx: &LayoutContext, node: Node, ctx: @FlowContext) -> @RenderBox {
        do node.read |n| {
            match n.kind {
                ~Text(string) => @UnscannedTextBox(RenderBoxData(node, ctx, self.next_box_id()), copy string),
                _ => fail ~"WAT error: why couldn't we make a text box?"
            }
        }
    }

    fn decide_box_type(node: Node, display: CSSDisplay) -> RenderBoxType {
        do node.read |n| {
            match n.kind {
                ~Doctype(*) | ~Comment(*) => fail ~"Hey, doctypes and comments shouldn't get here! They are display:none!",
                ~Text(*) => RenderBox_Text,
                ~Element(element) => {
                    // FIXME: Bad copy
                    match (copy element.kind, display) {
                        (~HTMLImageElement(d), _) if d.image.is_some() => RenderBox_Image,
//                      (_, Specified(_)) => GenericBox,
                        (_, _) => RenderBox_Generic // TODO: replace this with the commented lines
//                      (_, _) => fail ~"Can't create box for Node with non-specified 'display' type"
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::ops::RangeInclusive;

use itertools::Itertools;
use itertools::MinMaxResult;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        if a > 0. {
            Some((-b + d.sqrt()) / 2. / a)
        } else {
            Some((-b - d.sqrt()) / 2. / a)
        }
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = (*range.start() + *range.end()) as f64 / 2.;
    let b = initial as f64 + 0.5;
    let hit = solve_quadratic(-0.5, b, -middle)? as i32;

    if hit < 0 {
        // Should not happen because of the shape but for correctness
        None
    } else {
        let min_hit = (0..=hit)
            .rev()
            .take_while(|&n| range.contains(&position(initial, n)))
            .min();

        let max_hit = ((hit + 1)..)
            .take_while(|&n| range.contains(&position(initial, n)))
            .max();

        match (min_hit, max_hit) {
            (Some(min), Some(max)) => Some(min..=max),
            (Some(val), None) | (None, Some(val)) => Some(val..=val),
            _ => None,
        }
    }
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    if *range.end() <= position(x, x) {
        // Can and should come to a full stop
        let max = solve_quadratic(0.5, 0.5, -*range.end() as f64)? as i32;

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n)))
            .last()?;

        Some(min..=max)
    } else {
        // Might hit the target at speed
        let max = (x * x + 2 * *range.end() - x) / (2 * x);

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n.min(x))))
            .last()?;

        Some(min..=max)
    }
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value = |y_speed| {
        let mut time = find_hit(y_speed, &y_range)?;

        if time.any(|time| find_speed(time, &x_range).is_some()) {
            Some(position(y_speed, y_speed))
        } else {
            None
        }
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .filter_map(check_value)
        .max()
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        let time = find_hit(y_speed, &y_range)?;
        let range = time
            .filter_map(|time| find_speed(time, &x_range))
            .flat_map(|x| [*x.start(), *x.end()])
            .minmax();

        Some(match range {
            MinMaxResult::NoElements => 0,
            MinMaxResult::OneElement(_) => 1,
            MinMaxResult::MinMax(min, max) => max - min + 1,
        })
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max)
        .filter_map(num_options)
        .sum::<i32>()
        .to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)), Some(7..=7));
        assert_eq!(find_hit(3, &(-10..=-5)), Some(9..=9));
        assert_eq!(find_hit(0, &(-10..=-5)), Some(4..=5));
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<commit_msg>Use dedicated iterator instead of range<commit_after>use std::io::Read;
use std::ops::RangeInclusive;

use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        if a > 0. {
            Some((-b + d.sqrt()) / 2. / a)
        } else {
            Some((-b - d.sqrt()) / 2. / a)
        }
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> impl Iterator<Item = i32> + '_ {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = (*range.start() + *range.end()) as f64 / 2.;
    let b = initial as f64 + 0.5;
    let hit = if let Some(hit) = solve_quadratic(-0.5, b, -middle) {
        hit as i32
    } else {
        -1
    };

    (0..=hit)
        .rev()
        .take_while(move |&n| range.contains(&position(initial, n)))
        .chain(((hit + 1)..).take_while(move |&n| range.contains(&position(initial, n))))
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<(i32, i32)> {
    if *range.end() <= position(x, x) {
        // Can and should come to a full stop
        let max = solve_quadratic(0.5, 0.5, -*range.end() as f64)? as i32;

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n)))
            .last()?;

        Some((min, max))
    } else {
        // Might hit the target at speed
        let max = (x * x + 2 * *range.end() - x) / (2 * x);

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n.min(x))))
            .last()?;

        Some((min, max))
    }
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value =
        |y_speed| find_hit(y_speed, &y_range).any(|time| find_speed(time, &x_range).is_some());

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .rev()
        .find(|&speed| check_value(speed))
        .map(|speed| position(speed, speed))
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        find_hit(y_speed, &y_range)
            .filter_map(|time| find_speed(time, &x_range))
            .reduce(|(a_min, a_max), (b_min, b_max)| (a_min.min(b_min), a_max.max(b_max)))
            .map(|(min, max)| max - min + 1)
            .unwrap_or(0)
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max).map(num_options).sum::<i32>().to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)).collect::<Vec<_>>(), vec![7]);
        assert_eq!(find_hit(3, &(-10..=-5)).collect::<Vec<_>>(), vec![9]);
        assert_eq!(find_hit(0, &(-10..=-5)).collect::<Vec<_>>(), vec![4, 5]);
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;
use std::ops::Div;
use super::Projection;
use geometry::RegularSpace;
use geometry::dimensions::{BoundedDimension, Continuous};
use ndarray::Array1;
use utils::cartesian_product;

// TODO: Add learning rate scaling http://lis.csail.mit.edu/pubs/konidaris-aaai11a.pdf

#[derive(Serialize, Deserialize)]
pub struct Fourier {
    order: u8,
    limits: Vec<(f64, f64)>,
    coefficients: Vec<Vec<u8>>,
}

impl Fourier {
    pub fn new(order: u8, limits: Vec<(f64, f64)>) -> Self {
        let coefficients =
            cartesian_product(&vec![(0..(order+1)).collect::<Vec<u8>>(); limits.len()]);

        Fourier {
            order: order,
            limits: limits,
            coefficients: coefficients,
        }
    }

    pub fn from_space(order: u8, input_space: RegularSpace<Continuous>) -> Self {
        Fourier::new(order, input_space.iter().map(|d| d.limits()).collect())
    }
}

impl Projection<RegularSpace<Continuous>> for Fourier {
    fn project_onto(&self, input: &Vec<f64>, phi: &mut Array1<f64>) {
        let scaled_state = input.iter().enumerate().map(|(i, v)| {
            (v - self.limits[i].0) / (self.limits[i].1 - self.limits[i].0)
        }).collect::<Vec<f64>>();

        let mut z = 0.0;
        for (i, cfs) in self.coefficients.iter().enumerate() {
            let cx = scaled_state.iter().zip(cfs).fold(0.0, |acc, (v, c)| acc + (*c as f64)*v);

            let v = (PI*cx).cos();

            z += v.abs();
            phi[i] = v;
        }

        phi.mapv_inplace(|v| v/z);
    }

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

    fn size(&self) -> usize {
        (self.order as usize + 1).pow(self.dim() as u32)
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.order == other.order && self.limits == other.limits
    }
}

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

    #[test]
    fn test_order1_1d() {
        let f = Fourier::new(1, vec![(0.0, 1.0)]);

        assert_eq!(f.dim(), 1);
        assert_eq!(f.size(), 2);

        assert!(f.project(&vec![-1.0]).all_close(&arr1(&vec![0.5, -0.5]), 1e-6));
        assert!(f.project(&vec![-0.5]).all_close(&arr1(&vec![1.0, 0.0]), 1e-6));
        assert!(f.project(&vec![0.0]).all_close(&arr1(&vec![0.5, 0.5]), 1e-6));
        assert!(f.project(&vec![0.5]).all_close(&arr1(&vec![1.0, 0.0]), 1e-6));
        assert!(f.project(&vec![1.0]).all_close(&arr1(&vec![0.5, -0.5]), 1e-6));

        assert!(f.project(&vec![-2.0/3.0]).all_close(&arr1(&vec![2.0/3.0, -1.0/3.0]), 1e-6));
        assert!(f.project(&vec![-1.0/3.0]).all_close(&arr1(&vec![2.0/3.0, 1.0/3.0]), 1e-6));
        assert!(f.project(&vec![1.0/3.0]).all_close(&arr1(&vec![2.0/3.0, 1.0/3.0]), 1e-6));
        assert!(f.project(&vec![2.0/3.0]).all_close(&arr1(&vec![2.0/3.0, -1.0/3.0]), 1e-6));
    }

    #[test]
    fn test_order1_2d() {
        let f = Fourier::new(1, vec![(0.0, 1.0), (5.0, 6.0)]);

        assert_eq!(f.dim(), 2);
        assert_eq!(f.size(), 4);

        assert!(f.project(&vec![0.0, 5.0]).all_close(&arr1(&vec![0.25; 4]), 1e-6));
        assert!(f.project(&vec![0.5, 5.0]).all_close(&arr1(&vec![0.5, 0.5, 0.0, 0.0]), 1e-6));
        assert!(f.project(&vec![0.0, 5.5]).all_close(&arr1(&vec![0.5, 0.0, 0.5, 0.0]), 1e-6));
        assert!(f.project(&vec![0.5, 5.5]).all_close(&arr1(&vec![0.5, 0.0, 0.0, -0.5]), 1e-6));
        assert!(f.project(&vec![1.0, 5.5]).all_close(&arr1(&vec![0.5, 0.0, -0.5, 0.0]), 1e-6));
        assert!(f.project(&vec![0.5, 6.0]).all_close(&arr1(&vec![0.5, -0.5, 0.0, 0.0]), 1e-6));
        assert!(f.project(&vec![1.0, 6.0]).all_close(&arr1(&vec![0.25, -0.25, -0.25, 0.25]), 1e-6));
    }

    #[test]
    fn test_order2_1d() {
        let f = Fourier::new(2, vec![(0.0, 1.0)]);

        assert_eq!(f.dim(), 1);
        assert_eq!(f.size(), 3);

        assert!(f.project(&vec![-1.0]).all_close(&arr1(&vec![1.0/3.0, -1.0/3.0, 1.0/3.0]), 1e-6));
        assert!(f.project(&vec![-0.5]).all_close(&arr1(&vec![0.5, 0.0, -0.5]), 1e-6));
        assert!(f.project(&vec![0.0]).all_close(&arr1(&vec![1.0/3.0, 1.0/3.0, 1.0/3.0]), 1e-6));
        assert!(f.project(&vec![0.5]).all_close(&arr1(&vec![0.5, 0.0, -0.5]), 1e-6));
        assert!(f.project(&vec![1.0]).all_close(&arr1(&vec![1.0/3.0, -1.0/3.0, 1.0/3.0]), 1e-6));

        assert!(f.project(&vec![-2.0/3.0]).all_close(&arr1(&vec![0.5, -0.25, -0.25]), 1e-6));
        assert!(f.project(&vec![-1.0/3.0]).all_close(&arr1(&vec![0.5, 0.25, -0.25]), 1e-6));
        assert!(f.project(&vec![1.0/3.0]).all_close(&arr1(&vec![0.5, 0.25, -0.25]), 1e-6));
        assert!(f.project(&vec![2.0/3.0]).all_close(&arr1(&vec![0.5, -0.25, -0.25]), 1e-6));
    }
}
<commit_msg>fix(fa): robustify normalisation in Fourier projection<commit_after>use std::f64::consts::PI;
use std::ops::Div;
use super::Projection;
use geometry::RegularSpace;
use geometry::norms::{l1, l2};
use geometry::dimensions::{BoundedDimension, Continuous};
use ndarray::Array1;
use utils::cartesian_product;

// TODO: Add learning rate scaling http://lis.csail.mit.edu/pubs/konidaris-aaai11a.pdf
// TODO: Add builder which allows use to configure whether to use coefficient scaling or not.

#[derive(Clone, Serialize, Deserialize)]
pub struct Fourier {
    order: u8,
    limits: Vec<(f64, f64)>,
    coefficients: Vec<Vec<f64>>,
}

impl Fourier {
    pub fn new(order: u8, limits: Vec<(f64, f64)>) -> Self {
        let coefficients = Fourier::make_coefficients(order, limits.len());

        Fourier {
            order: order,
            limits: limits,
            coefficients: coefficients,
        }
    }

    pub fn from_space(order: u8, input_space: RegularSpace<Continuous>) -> Self {
        Fourier::new(order, input_space.iter().map(|d| d.limits()).collect())
    }

    fn make_coefficients(order: u8, dim: usize) -> Vec<Vec<f64>> {
        let dcs = vec![(0..(order+1)).map(|v| v as f64).collect::<Vec<f64>>(); dim];
        let mut coefficients = cartesian_product(&dcs).iter().skip(1).map(|cfs| {
            let z = l2(&cfs);

            cfs.iter().map(|c| c/z).collect()
        }).collect::<Vec<Vec<f64>>>();

        coefficients.sort_by(|a, b| b.partial_cmp(a).unwrap());
        coefficients.dedup();

        coefficients
    }
}

impl Projection<RegularSpace<Continuous>> for Fourier {
    fn project_onto(&self, input: &Vec<f64>, phi: &mut Array1<f64>) {
        let scaled_state = input.iter().enumerate().map(|(i, v)| {
            (v - self.limits[i].0) / (self.limits[i].1 - self.limits[i].0)
        }).collect::<Vec<f64>>();

        for (i, cfs) in self.coefficients.iter().enumerate() {
            let cx = scaled_state.iter().zip(cfs).fold(0.0, |acc, (v, c)| acc + *c*v);

            phi[i] = (PI*cx).cos();
        }

        let z = l1(phi.as_slice().unwrap());
        if z.abs() > 1e-6 {
            phi.mapv_inplace(|v| v/z);
        }
    }

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

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

    fn equivalent(&self, other: &Self) -> bool {
        self.order == other.order && self.limits == other.limits
    }
}

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

    #[test]
    fn test_pruning() {
        assert_eq!(Fourier::new(1, vec![(0.0, 1.0)]).dim(), 1);
        assert_eq!(Fourier::new(2, vec![(0.0, 1.0)]).dim(), 1);
        assert_eq!(Fourier::new(3, vec![(0.0, 1.0)]).dim(), 1);
        assert_eq!(Fourier::new(4, vec![(0.0, 1.0)]).dim(), 1);
        assert_eq!(Fourier::new(5, vec![(0.0, 1.0)]).dim(), 1);
    }

    #[test]
    fn test_symmetry() {
        let f = Fourier::new(1, vec![(0.0, 1.0)]);

        assert_eq!(f.project(&vec![-1.0]), f.project(&vec![1.0]));
        assert_eq!(f.project(&vec![-0.5]), f.project(&vec![0.5]));
    }

    #[test]
    fn test_order1_1d() {
        let f = Fourier::new(1, vec![(0.0, 1.0)]);

        assert_eq!(f.dim(), 1);
        assert_eq!(f.size(), 1);

        assert!(f.project(&vec![-1.0]).all_close(&arr1(&vec![-1.0]), 1e-6));
        assert!(f.project(&vec![-0.5]).all_close(&arr1(&vec![0.0]), 1e-6));
        assert!(f.project(&vec![0.0]).all_close(&arr1(&vec![1.0]), 1e-6));
        assert!(f.project(&vec![0.5]).all_close(&arr1(&vec![0.0]), 1e-6));
        assert!(f.project(&vec![1.0]).all_close(&arr1(&vec![-1.0]), 1e-6));

        assert!(f.project(&vec![-2.0/3.0]).all_close(&arr1(&vec![-1.0]), 1e-6));
        assert!(f.project(&vec![-1.0/3.0]).all_close(&arr1(&vec![1.0]), 1e-6));
        assert!(f.project(&vec![1.0/3.0]).all_close(&arr1(&vec![1.0]), 1e-6));
        assert!(f.project(&vec![2.0/3.0]).all_close(&arr1(&vec![-1.0]), 1e-6));
    }

    #[test]
    fn test_order2_1d() {
        let f1 = Fourier::new(1, vec![(0.0, 1.0)]);
        let f2 = Fourier::new(2, vec![(0.0, 1.0)]);

        assert_eq!(f2.dim(), f1.dim());
        assert_eq!(f2.size(), f2.size());

        assert_eq!(f2.project(&vec![-1.0]), f1.project(&vec![-1.0]));
        assert_eq!(f2.project(&vec![-0.5]), f1.project(&vec![-0.5]));
        assert_eq!(f2.project(&vec![0.0]), f1.project(&vec![0.0]));
        assert_eq!(f2.project(&vec![0.5]), f1.project(&vec![0.5]));
        assert_eq!(f2.project(&vec![1.0]), f1.project(&vec![1.0]));

        assert_eq!(f2.project(&vec![-2.0/3.0]), f1.project(&vec![-2.0/3.0]));
        assert_eq!(f2.project(&vec![-1.0/3.0]), f1.project(&vec![-1.0/3.0]));
        assert_eq!(f2.project(&vec![1.0/3.0]), f1.project(&vec![1.0/3.0]));
        assert_eq!(f2.project(&vec![2.0/3.0]), f1.project(&vec![2.0/3.0]));
    }

    #[test]
    fn test_order1_2d() {
        let f = Fourier::new(1, vec![(0.0, 1.0), (5.0, 6.0)]);

        assert_eq!(f.dim(), 2);
        assert_eq!(f.size(), 3);

        assert!(f.project(&vec![0.0, 5.0]).all_close(&arr1(&vec![1.0/3.0; 3]), 1e-6));
        assert!(f.project(&vec![0.5, 5.0]).all_close(&arr1(&vec![4.24042024e-17, 3.07486821e-1, 6.92513179e-1]), 1e-6));
        assert!(f.project(&vec![0.0, 5.5]).all_close(&arr1(&vec![6.92513179e-1, 3.07486821e-1, 4.24042024e-17]), 1e-6));
        assert!(f.project(&vec![0.5, 5.5]).all_close(&arr1(&vec![1.01093534e-16, -1.0, 1.01093534e-16]), 1e-6));
        assert!(f.project(&vec![1.0, 5.5]).all_close(&arr1(&vec![-5.04567213e-1, -4.95432787e-1, 3.08958311e-17]), 1e-6));
        assert!(f.project(&vec![0.5, 6.0]).all_close(&arr1(&vec![3.08958311e-17, -4.95432787e-1, -5.04567213e-1]), 1e-6));
        assert!(f.project(&vec![1.0, 6.0]).all_close(&arr1(&vec![-0.44125654, -0.11748691, -0.44125654]), 1e-6));
    }

    #[test]
    fn test_order2_2d() {
        let f = Fourier::new(2, vec![(0.0, 1.0), (5.0, 6.0)]);

        assert_eq!(f.dim(), 2);
        assert_eq!(f.size(), 5);

        assert!(f.project(&vec![0.0, 5.0]).all_close(&arr1(&vec![0.2; 5]), 1e-6));
        assert!(f.project(&vec![0.5, 5.0]).all_close(&arr1(&vec![2.58110397e-17, 6.95831686e-2,
                                                                 1.87164340e-1, 3.21726225e-1,
                                                                 4.21526267e-1]), 1e-6));
        assert!(f.project(&vec![0.5, 5.5]).all_close(&arr1(&vec![3.76070090e-17, -3.13998939e-1,
                                                                 -3.72002121e-1, -3.13998939e-1,
                                                                 3.76070090e-17]), 1e-6));
        assert!(f.project(&vec![0.5, 6.0]).all_close(&arr1(&vec![1.58656439e-17, -2.44984612e-1,
                                                                 -2.54414913e-1, -2.41494847e-1,
                                                                 -2.59105628e-1]), 1e-6));
        assert!(f.project(&vec![1.0, 6.0]).all_close(&arr1(&vec![-0.31048999, -0.1481752,
                                                                 -0.08266962, -0.1481752,
                                                                 -0.31048999]), 1e-6));
    }
}
<|endoftext|>


<commit_before>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a dropbox file conflict encoded in the file name in the form:
//
//    `<base_name> (<host>'s conflicted copy <date>).txt`
//
// e.g:
//
//    `x_original (blub's conflicted copy 2011-04-30).txt`
//
// would return:
//
//    Some("x_original.txt", "Version 2011-04-30 from blub")
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   parse_internal(file_name).ok()
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   let mut parser = Parser::new(file_name);
   let mut base_name = parser.take_while(|c| c != '(');

   // drops the whitespace before the '('
   base_name.pop();

   try!(parser.skip("("));
   let host = parser.take_while(|c| c != '\'');

   try!(parser.skip("'s conflicted copy "));

   let version = parser.take_while(|c| c != ')');
   try!(parser.skip(")"));

   if ! parser.eof() {
      let extension = parser.take_till_eof();
      base_name.push_str(extension.as_slice());
   }

   let details = format!("Version {} from {}", version, host);
   Ok((base_name, details))
}

#[test]
fn tests()
{
   test_str("a_original (blub's conflicted copy 2011-04-30)", "a_original", "Version 2011-04-30 from blub");
   test_str("a_original (blub's conflicted copy 2011-04-30).txt", "a_original.txt", "Version 2011-04-30 from blub");
   test_str("original (machine's conflicted copy 2011-04-29)", "original", "Version 2011-04-29 from machine");
   test_str("z_original (laptop's conflicted copy 2011-04-28).qay", "z_original.qay", "Version 2011-04-28 from laptop");
}

#[cfg(test)]
fn test_str(file_name: &str, orig_name: &str, details: &str)
{
   println!("test: {}", file_name);
   match parse_internal(file_name) {
      Ok((name, det)) => {
         assert_eq!(orig_name.to_string(), name);
         assert_eq!(details.to_string()  , det);
      }

      Err(err) => assert!(false, err)
   }
}
<commit_msg>Extend dropbox tests<commit_after>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a dropbox file conflict encoded in the file name in the form:
//
//    `<base_name> (<host>'s conflicted copy <date>).txt`
//
// e.g:
//
//    `x_original (blub's conflicted copy 2011-04-30).txt`
//
// would return:
//
//    Some("x_original.txt", "Version 2011-04-30 from blub")
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   parse_internal(file_name).ok()
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   let mut parser = Parser::new(file_name);
   let mut base_name = parser.take_while(|c| c != '(');

   // drops the whitespace before the '('
   base_name.pop();

   try!(parser.skip("("));
   let host = parser.take_while(|c| c != '\'');

   try!(parser.skip("'s conflicted copy "));

   let version = parser.take_while(|c| c != ')');
   try!(parser.skip(")"));

   if ! parser.eof() {
      let extension = parser.take_till_eof();
      base_name.push_str(extension.as_slice());
   }

   let details = format!("Version {} from {}", version, host);
   Ok((base_name, details))
}

#[test]
fn tests()
{
   test_str("a_original (blub's conflicted copy 2011-04-30)",
            Ok(("a_original".to_string(), "Version 2011-04-30 from blub".to_string())));

   test_str("a_original (blub's conflicted copy 2011-04-30).txt",
            Ok(("a_original.txt".to_string(), "Version 2011-04-30 from blub".to_string())));

   test_str("original (machine's conflicted copy 2011-04-29)",
            Ok(("original".to_string(), "Version 2011-04-29 from machine".to_string())));

   test_str("z_original (laptop's conflicted copy 2011-04-28).qay",
            Ok(("z_original.qay".to_string(), "Version 2011-04-28 from laptop".to_string())));

   test_str("z_original (blub's conflicted copy 2011-04-30)",
            Ok(("z_original".to_string(), "Version 2011-04-30 from blub".to_string())));

   test_str("z_original (laptop's conflicted copy 2011-04-28)",
            Ok(("z_original".to_string(), "Version 2011-04-28 from laptop".to_string())));

   test_str("z_original (machine's conflicted copy 2011-04-29)",
            Ok(("z_original".to_string(), "Version 2011-04-29 from machine".to_string())));

   test_str("z_original", Err("Couldn't skip str '('!".to_string()));
}

#[cfg(test)]
fn test_str(file_name: &str, result: Result<(OrigFileName, Details), ParseError>)
{
   println!("test: {}", file_name);
   assert_eq!(parse_internal(file_name), result);
}
<|endoftext|>


<commit_before>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;

use crate::{per_ns::PerNs, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    items: FxHashMap<Name, Resolution>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| {
            (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: false })
        })
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    // Prefer Module
    Module,
    // Prefer Other Types
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
        //FIXME: shadowing
        self.items.iter().chain(BUILTIN_SCOPE.iter())
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.entries()
            .filter_map(|(_name, res)| if !res.import { Some(res.def) } else { None })
            .flat_map(|per_ns| {
                per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
            })
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.items
            .iter()
            .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&Resolution> {
        match shadow {
            BuiltinShadowMode::Module => self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
            BuiltinShadowMode::Other => {
                let item = self.items.get(name);
                if let Some(res) = item {
                    if let Some(ModuleDefId::ModuleId(_)) = res.def.take_types() {
                        return BUILTIN_SCOPE.get(name).or(item);
                    }
                }

                item.or_else(|| BUILTIN_SCOPE.get(name))
            }
        }
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.items.values().filter_map(|r| match r.def.take_types() {
            Some(ModuleDefId::TraitId(t)) => Some(t),
            _ => None,
        })
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, res: &Resolution, import: bool) -> bool {
        let mut changed = false;
        let existing = self.items.entry(name.clone()).or_default();

        if existing.def.types.is_none() && res.def.types.is_some() {
            existing.def.types = res.def.types;
            existing.import = import || res.import;
            changed = true;
        }
        if existing.def.values.is_none() && res.def.values.is_some() {
            existing.def.values = res.def.values;
            existing.import = import || res.import;
            changed = true;
        }
        if existing.def.macros.is_none() && res.def.macros.is_some() {
            existing.def.macros = res.def.macros;
            existing.import = import || res.import;
            changed = true;
        }

        if existing.def.is_none() && res.def.is_none() && !existing.import && res.import {
            existing.import = res.import;
        }
        changed
    }

    pub(crate) fn collect_resolutions(&self) -> Vec<(Name, Resolution)> {
        self.items.iter().map(|(name, res)| (name.clone(), res.clone())).collect()
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Resolution {
    /// None for unresolved
    pub def: PerNs,
    pub(crate) import: bool,
}
<commit_msg>Minor rename<commit_after>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;

use crate::{per_ns::PerNs, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    visible: FxHashMap<Name, Resolution>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| {
            (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: false })
        })
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    // Prefer Module
    Module,
    // Prefer Other Types
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
        //FIXME: shadowing
        self.visible.iter().chain(BUILTIN_SCOPE.iter())
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.entries()
            .filter_map(|(_name, res)| if !res.import { Some(res.def) } else { None })
            .flat_map(|per_ns| {
                per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
            })
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.visible
            .iter()
            .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&Resolution> {
        match shadow {
            BuiltinShadowMode::Module => self.visible.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
            BuiltinShadowMode::Other => {
                let item = self.visible.get(name);
                if let Some(res) = item {
                    if let Some(ModuleDefId::ModuleId(_)) = res.def.take_types() {
                        return BUILTIN_SCOPE.get(name).or(item);
                    }
                }

                item.or_else(|| BUILTIN_SCOPE.get(name))
            }
        }
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.visible.values().filter_map(|r| match r.def.take_types() {
            Some(ModuleDefId::TraitId(t)) => Some(t),
            _ => None,
        })
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, res: &Resolution, import: bool) -> bool {
        let mut changed = false;
        let existing = self.visible.entry(name.clone()).or_default();

        if existing.def.types.is_none() && res.def.types.is_some() {
            existing.def.types = res.def.types;
            existing.import = import || res.import;
            changed = true;
        }
        if existing.def.values.is_none() && res.def.values.is_some() {
            existing.def.values = res.def.values;
            existing.import = import || res.import;
            changed = true;
        }
        if existing.def.macros.is_none() && res.def.macros.is_some() {
            existing.def.macros = res.def.macros;
            existing.import = import || res.import;
            changed = true;
        }

        if existing.def.is_none() && res.def.is_none() && !existing.import && res.import {
            existing.import = res.import;
        }
        changed
    }

    pub(crate) fn collect_resolutions(&self) -> Vec<(Name, Resolution)> {
        self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect()
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Resolution {
    /// None for unresolved
    pub def: PerNs,
    pub(crate) import: bool,
}
<|endoftext|>