<commit_before>use vec_shift::Shift;
use std::str::FromStr;
use std::error::Error as StdError;
use std::fmt;
use utils::parse_quotes;

/// Defines how an operation on an `Args` method failed.
#[derive(Debug)]
pub enum Error<E: StdError> {
    /// "END-OF-STRING", more precisely, there isn't anything to parse anymore.
    Eos,
    /// A parsing operation failed; the error in it can be of any returned from the `FromStr`
    /// trait.
    Parse(E),
}

impl<E: StdError> From<E> for Error<E> {
    fn from(e: E) -> Self {
        Error::Parse(e)
    }
}

impl<E: StdError> StdError for Error<E> {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            Eos => "end-of-string",
            Parse(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;

        match *self {
            Parse(ref e) => Some(e),
            _ => None,
        }
    }
}

impl<E: StdError> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Eos => write!(f, "end of string"),
            Parse(ref e) => fmt::Display::fmt(&e, f),
        }
    }
}

type Result<T, E> = ::std::result::Result<T, Error<E>>;

/// A utility struct for handling arguments of a command.
///
/// General functionality is done via removing an item, parsing it, then returning it; this however
/// can be mitigated with the `*_n` methods, which just parse and return.
#[derive(Clone, Debug)]
pub struct Args {
    delimiter: String,
    delimiter_split: Vec<String>,
}

impl Args {
    pub fn new(message: &str, delimiter: &str) -> Self {
        let split = if message.trim().is_empty() {
            Vec::new()
        } else {
            message.split(delimiter).map(|s| s.to_string()).collect()
        };

        Args {
            delimiter: delimiter.to_string(),
            delimiter_split: split,
        }
    }

    /// Removes the first element, parses it to a specific type if necessary, returns.
    pub fn single<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .shift()
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Like [`single`], but doesn't remove the element.
    ///
    /// [`single`]: #method.single
    pub fn single_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .get(0)
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Skips if there's a first element, but also returns it.
    pub fn skip(&mut self) -> Option<String> { self.delimiter_split.shift() }

    /// Like [`skip`], but allows for multiple at once.
    ///
    /// [`skip`]: #method.skip
    pub fn skip_for(&mut self, i: u32) -> Option<Vec<String>> {
        let mut vec = Vec::with_capacity(i as usize);

        for _ in 0..i {
            vec.push(try_opt!(self.delimiter_split.shift()));
        }

        Some(vec)
    }

    /// Like [`single`], but takes quotes into account.
    ///
    /// [`single`]: #method.single
    pub fn single_quoted<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(&self.delimiter_split.shift().ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`single_quoted`], but doesn't remove the element.
    ///
    /// [`single_quoted`]: #method.single_quoted
    pub fn single_quoted_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(self.delimiter_split.get(0).ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`list`], but takes quotes into account.
    ///
    /// [`list`]: #method.list
    pub fn multiple_quoted<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        parse_quotes(&self.delimiter_split.join(&self.delimiter))
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// Empty outs the internal vector while parsing (if necessary) and returning them
    pub fn list<T: FromStr>(mut self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        Iter::<T>::new(&mut self).collect()
    }

    /// Provides an iterator of items: (`T: FromStr`) `Result<T, T::Err>`.
    pub fn iter<T: FromStr>(&mut self) -> Iter<T> where T::Err: StdError  {
        Iter::new(self)
    }

    /// This method is just `internal_vector.join(delimiter)`
    pub fn full(&self) -> String { self.delimiter_split.join(&self.delimiter) }

    /// Returns the first argument that can be converted and removes it from the list.
    pub fn find<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        match self.delimiter_split
                  .iter()
                  .position(|e| e.parse::<T>().is_ok())
        {
            Some(index) => {
                let value = self.delimiter_split
                    .get(index)
                    .ok_or(Error::Eos)?
                    .parse::<T>()?;

                self.delimiter_split.remove(index);

                Ok(value)
            },
            _ => Err(Error::Eos),
        }
    }

    /// Returns the first argument that can be converted and does not remove it from the list.
    pub fn find_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .iter()
            .find(|e| e.parse::<T>().is_ok())
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }
}

impl ::std::ops::Deref for Args {
    type Target = [String];

    fn deref(&self) -> &Self::Target { &self.delimiter_split }
}

use std::marker::PhantomData;

/// Provides `list`'s functionality, but as an iterator.
pub struct Iter<'a, T: FromStr> where T::Err: StdError {
    args: &'a mut Args,
    _marker: PhantomData<T>,
}

impl<'a, T: FromStr> Iter<'a, T> where T::Err: StdError {
    fn new(args: &'a mut Args) -> Self {
        Iter { args, _marker: PhantomData }
    }
}

impl<'a, T: FromStr> Iterator for Iter<'a, T> where T::Err: StdError  {
    type Item = Result<T, T::Err>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.args.is_empty() {
            None
        } else {
            Some(self.args.single::<T>())
        }
    }
}
<commit_msg>Add `PartialEq` impls and doc tests to `Args`<commit_after>use vec_shift::Shift;
use std::str::FromStr;
use std::error::Error as StdError;
use std::fmt;
use utils::parse_quotes;

/// Defines how an operation on an `Args` method failed.
#[derive(Debug)]
pub enum Error<E: StdError> {
    /// "END-OF-STRING", more precisely, there isn't anything to parse anymore.
    Eos,
    /// A parsing operation failed; the error in it can be of any returned from the `FromStr`
    /// trait.
    Parse(E),
}

impl<E: StdError> From<E> for Error<E> {
    fn from(e: E) -> Self {
        Error::Parse(e)
    }
}

impl<E: StdError> StdError for Error<E> {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            Eos => "end-of-string",
            Parse(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;

        match *self {
            Parse(ref e) => Some(e),
            _ => None,
        }
    }
}

impl<E: StdError> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Eos => write!(f, "end of string"),
            Parse(ref e) => fmt::Display::fmt(&e, f),
        }
    }
}

type Result<T, E> = ::std::result::Result<T, Error<E>>;

/// A utility struct for handling arguments of a command.
///
/// General functionality is done via removing an item, parsing it, then returning it; this however
/// can be mitigated with the `*_n` methods, which just parse and return.
#[derive(Clone, Debug)]
pub struct Args {
    delimiter: String,
    delimiter_split: Vec<String>,
}

impl Args {
    pub fn new(message: &str, delimiter: &str) -> Self {
        let split = if message.trim().is_empty() {
            Vec::new()
        } else {
            message.split(delimiter).map(|s| s.to_string()).collect()
        };

        Args {
            delimiter: delimiter.to_string(),
            delimiter_split: split,
        }
    }

    /// Removes the first element, parses it to a specific type if necessary, returns.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("42 69", " ");
    ///
    /// assert_eq!(args.single::<i32>().unwrap(), 42);
    /// assert_eq!(args, ["69"]);
    /// ```
    pub fn single<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .shift()
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Like [`single`], but doesn't remove the element.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let args = Args::new("42 69", " ");
    ///
    /// assert_eq!(args.single_n::<i32>().unwrap(), 42);
    /// assert!(args == ["42", "69"]);
    /// ```
    ///
    /// [`single`]: #method.single
    pub fn single_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .get(0)
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Skips if there's a first element, but also returns it.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("42 69", " ");
    ///
    /// assert_eq!(args.skip().unwrap(), "42");
    /// assert_eq!(args, ["69"]);
    /// ```
    pub fn skip(&mut self) -> Option<String> { self.delimiter_split.shift() }

    /// Like [`skip`], but allows for multiple at once.
    ///
    /// # Examples
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("42 69 88 99", " ");
    ///
    /// assert_eq!(*args.skip_for(3).unwrap(), ["42".to_string(), "69".to_string(), "88".to_string()]);
    /// assert_eq!(args, ["99"]);
    /// ```
    ///
    /// [`skip`]: #method.skip
    pub fn skip_for(&mut self, i: u32) -> Option<Vec<String>> {
        let mut vec = Vec::with_capacity(i as usize);

        for _ in 0..i {
            vec.push(try_opt!(self.delimiter_split.shift()));
        }

        Some(vec)
    }

    /// Like [`single`], but takes quotes into account.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new(r#""42"#, " ");
    ///
    /// assert_eq!(args.single_quoted::<i32>().unwrap(), 42);
    /// assert!(args.is_empty());
    /// ```
    ///
    /// [`single`]: #method.single
    pub fn single_quoted<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(&self.delimiter_split.shift().ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`single_quoted`], but doesn't remove the element.
    ///
    /// [`single_quoted`]: #method.single_quoted
    pub fn single_quoted_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(self.delimiter_split.get(0).ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`list`], but takes quotes into account.
    ///
    /// [`list`]: #method.list
    pub fn multiple_quoted<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        parse_quotes(&self.delimiter_split.join(&self.delimiter))
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// Empty outs the internal vector while parsing (if necessary) and returning them
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("42 69", " ");
    ///
    /// assert_eq!(*args.list::<i32>().unwrap(), [42, 69]);
    /// ```
    pub fn list<T: FromStr>(mut self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        Iter::<T>::new(&mut self).collect()
    }

    /// Provides an iterator of items: (`T: FromStr`) `Result<T, T::Err>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("3 4", " ");
    ///
    /// assert_eq!(*args.iter::<i32>().map(|num| num.unwrap().pow(2)).collect::<Vec<_>>(), [9, 16]);
    /// assert!(args.is_empty());
    /// ```
    pub fn iter<T: FromStr>(&mut self) -> Iter<T> where T::Err: StdError  {
        Iter::new(self)
    }

    /// This method is just `internal_vector.join(delimiter)`
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("42 69", " ");
    ///
    /// assert_eq!(args.full(), "42 69");
    /// ```
    pub fn full(&self) -> String { self.delimiter_split.join(&self.delimiter) }

    /// Returns the first argument that can be converted and removes it from the list.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let mut args = Args::new("c47 69", " ");
    ///
    /// assert_eq!(args.find::<i32>().unwrap(), 69);
    /// assert_eq!(args, ["c47"]);
    /// ```
    pub fn find<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        match self.delimiter_split
                  .iter()
                  .position(|e| e.parse::<T>().is_ok())
        {
            Some(index) => {
                let value = self.delimiter_split
                    .get(index)
                    .ok_or(Error::Eos)?
                    .parse::<T>()?;

                self.delimiter_split.remove(index);

                Ok(value)
            },
            _ => Err(Error::Eos),
        }
    }

    /// Returns the first argument that can be converted and does not remove it from the list.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::framework::standard::Args;
    ///
    /// let args = Args::new("c47 69", " ");
    ///
    /// assert_eq!(args.find_n::<i32>().unwrap(), 69);
    /// assert!(args == ["c47", "69"]);
    /// ```
    pub fn find_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .iter()
            .find(|e| e.parse::<T>().is_ok())
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }
}

impl ::std::ops::Deref for Args {
    type Target = [String];

    fn deref(&self) -> &Self::Target { &self.delimiter_split }
}

impl<'a> PartialEq<[&'a str]> for Args {
    fn eq(&self, other: &[&str]) -> bool {
        let mut b = true;

        for (s, o) in self.delimiter_split.iter().zip(other.iter()) {
            if s != o {
                b = false;
            }
        }

        b
    }
}

macro_rules! impl_slices {
    ($($num:expr),*) => {
        impl<'a> PartialEq<[&'a str; 0]> for Args {
            fn eq(&self, _: &[&str; 0]) -> bool {
                self.delimiter_split.is_empty()
            }
        }

        $(
            impl<'a> PartialEq<[&'a str; $num]> for Args {
                fn eq(&self, other: &[&str; $num]) -> bool {
                    <Args as PartialEq<[&str]>>::eq(self, &other[..])
                }
            }
        )*
    }
}

impl_slices! {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
    29, 30, 31, 32
}

impl PartialEq for Args {
    fn eq(&self, other: &Self) -> bool {
        self.delimiter_split == other.delimiter_split
    }
}

impl Eq for Args {}

use std::marker::PhantomData;

/// Provides `list`'s functionality, but as an iterator.
pub struct Iter<'a, T: FromStr> where T::Err: StdError {
    args: &'a mut Args,
    _marker: PhantomData<T>,
}

impl<'a, T: FromStr> Iter<'a, T> where T::Err: StdError {
    fn new(args: &'a mut Args) -> Self {
        Iter { args, _marker: PhantomData }
    }
}

impl<'a, T: FromStr> Iterator for Iter<'a, T> where T::Err: StdError  {
    type Item = Result<T, T::Err>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.args.is_empty() {
            None
        } else {
            Some(self.args.single::<T>())
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::RwLock;
use std::time::SystemTime;
use board::*;
use depth::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Decides when the search must be terminated.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    extrapolation_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    #[allow(unused_variables)]
    fn new(position: &S::SearchNode, time: RemainingTime) -> StdTimeManager {
        // Get our remaining time and increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves till the next time control, or
        // guess the number of moves till the end of the game.
        let n = match time.movestogo.unwrap_or(0) {
            0 => 40,
            n => n,
        } as f64;

        // Calculate an approximation for the total time we have till
        // the next time control or the end of the game.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            extrapolation_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think a fraction of a second in order to
                // find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDER.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    #[allow(unused_variables)]
    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        let &SearchReport { ref depth, ref searched_nodes, .. } = report;
        if *depth > self.depth {
            self.depth = *depth;
            if *searched_nodes > 100 {
                let t = elapsed_millis(&self.started_at);
                let depth = *depth as f64;
                let searched_nodes = *searched_nodes as f64;

                // We maintain a list of data points so as to be able
                // to intelligently guess how much time it will take
                // for the next search depth to complete. (We apply
                // exponential regression over the last `M` points in
                // the list.)
                const M: usize = 5;
                self.extrapolation_points.push((depth, searched_nodes.ln()));
                let expected_duration = match self.extrapolation_points.len() {
                    n if n >= M => {
                        let last_m = &self.extrapolation_points[n - M..];
                        let factor = extrapolate(last_m, depth + 1.0).exp() / searched_nodes;

                        // Update `BRANCHING_FACTOR`. This is an
                        // average branching factor calculated over
                        // the last few moves.
                        if n == M {
                            let mut bf = BRANCHING_FACTOR.write().unwrap();
                            *bf = (*bf * 2.0 + factor) / 3.0;
                        }

                        factor * t
                    }
                    _ => *BRANCHING_FACTOR.read().unwrap() * t,
                };

                // We try to stay as close as possible to the allotted
                // time, without crossing the hard limit.
                self.must_play = expected_duration > self.hard_limit ||
                                 expected_duration > self.allotted_time &&
                                 expected_duration - self.allotted_time > self.allotted_time - t;
            }
        }
    }

    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play || elapsed_millis(&self.started_at) > self.hard_limit
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDER.write().unwrap() = true,
                "false" => *PONDER.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDER: RwLock<bool> = RwLock::new(false);
    static ref BRANCHING_FACTOR: RwLock<f64> = RwLock::new(2.0);
}

/// A helper function. It calculates the elapsed milliseconds since a
/// given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap();
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// A helper function. It linearly extrapolates the value y(x) using
/// the (x, y) values in `points` as reference.
fn extrapolate(points: &[(f64, f64)], x: f64) -> f64 {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    slope * x + intercept
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::extrapolate;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let y = extrapolate(&points, x);
        assert!(4.99 < y && y < 5.01);
    }
}
<commit_msg>beautify<commit_after>//! Implements `StdTimeManager`.

use std::sync::RwLock;
use std::time::SystemTime;
use board::*;
use depth::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Implements the `TimeManager` trait.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    extrapolation_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    fn new(position: &S::SearchNode, time: RemainingTime) -> StdTimeManager {
        // Get our remaining time and increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves till the next time control, or
        // guess the number of moves till the end of the game.
        let n = match time.movestogo.unwrap_or(0) {
            0 => 40,
            n => n,
        } as f64;

        // Calculate an approximation for the total time we have till
        // the next time control or the end of the game.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            extrapolation_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think a fraction of a second in order to
                // find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDERING_IS_ALLOWED.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        let &SearchReport { ref depth, ref searched_nodes, .. } = report;
        if *depth > self.depth {
            self.depth = *depth;
            if *searched_nodes < 100 {
                // We ignore the first few completed depths, because
                // they are calculated almost instantaneously.
                return;
            }
            let t = elapsed_millis(&self.started_at);
            let depth = *depth as f64;
            let searched_nodes = *searched_nodes as f64;

            // We maintain a list of data points so as to be able to
            // intelligently guess how much time it will take for the
            // next search depth to complete. (We apply an exponential
            // regression over the last `M` points in the list.)
            const M: usize = 5;
            self.extrapolation_points.push((depth, searched_nodes.ln()));
            let expected_duration = match self.extrapolation_points.len() {
                n if n >= M => {
                    let last_m = &self.extrapolation_points[n - M..];
                    let factor = extrapolate(last_m, depth + 1.0).exp() / searched_nodes;

                    // Update `BRANCHING_FACTOR`. This is an average
                    // branching factor calculated over the last few
                    // moves.
                    if n == M {
                        let mut bf = BRANCHING_FACTOR.write().unwrap();
                        *bf = (*bf * 2.0 + factor) / 3.0;
                    }

                    factor * t
                }
                _ => *BRANCHING_FACTOR.read().unwrap() * t,
            };

            // We try to stay as close as possible to the allotted
            // time, without crossing the hard limit.
            self.must_play = expected_duration > self.hard_limit ||
                             expected_duration > self.allotted_time &&
                             expected_duration - self.allotted_time > self.allotted_time - t;
        }
    }

    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play || elapsed_millis(&self.started_at) > self.hard_limit
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDERING_IS_ALLOWED.write().unwrap() = true,
                "false" => *PONDERING_IS_ALLOWED.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDERING_IS_ALLOWED: RwLock<bool> = RwLock::new(false);
    static ref BRANCHING_FACTOR: RwLock<f64> = RwLock::new(2.0);
}

/// A helper function. It calculates the elapsed milliseconds since a
/// given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap();
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// A helper function. It linearly extrapolates the value y(x) using
/// the (x, y) values in `points` as a reference.
fn extrapolate(points: &[(f64, f64)], x: f64) -> f64 {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    slope * x + intercept
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::extrapolate;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let y = extrapolate(&points, x);
        assert!(4.99 < y && y < 5.01);
    }
}
<|endoftext|>


<commit_before>/* diosix abstracted hardware manager
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

use alloc::vec::Vec;
use spin::Mutex;
use platform::devices::Devices;
use platform::physmem::{PhysMemBase, PhysMemSize};
use platform::timer;
use super::error::Cause;
use super::pcore;

lazy_static!
{
    /* acquire HARDWARE before accessing any system hardware */
    static ref HARDWARE: Mutex<Option<Devices>> = Mutex::new(None);

    /* ID of the physical core that last obtained the HARDWARE lock */
    static ref HARDWARE_PREV_OWNER: Mutex<Option<pcore::PhysicalCoreID>> = Mutex::new(None);
}

/* parse_and_init
   Parse a device tree structure to create a base set of hardware devices.
   also initialize the devices so they can be used.
   call before using acquire_hardware_lock() to access HARDWARE.
   => device_tree = byte slice containing the device tree in physical memory
   <= return Ok for success, or error code on failure
*/
pub fn parse_and_init(dtb: &[u8]) -> Result<(), Cause>
{
    if let Ok(dt) = Devices::new(dtb)
    {
        *(HARDWARE.lock()) = Some(dt);
        return Ok(())
    }
    else
    {
        return Err(Cause::DeviceTreeBad);
    }
}

#[derive(Copy, Clone)]
enum LockAttempts
{
    Once,
    Multiple
}

/* acquire a lock on HARDWARE. If this physical CPU core is supposed to be
   holding it already, then bust the lock so that it and others can
   access it again. Use this function to safely access HARDWARE.
   => attempts = try just Once or Multiple times to acquire lock
   <= Some MutexGuard containing the device structure, or None for unsuccessful */
fn acquire_hardware_lock(attempts_allowed: LockAttempts) -> Option<spin::MutexGuard<'static, Option<platform::devices::Devices>>>
{
    loop
    {
        /* set to true if an attempt was made no matter how successful */
        let mut attempt = false;

        match HARDWARE.try_lock()
        {
            /* successfully obtained the hardware lock though we're racing
            the None branch so don't assume we'll get HARDWARE_PREV_OWNER */
            Some(lock) =>
            {
                /* try to get the HARDWARE_PREV_OWNER lock, too, or fail out */
                if let Some(mut owner_lock) = HARDWARE_PREV_OWNER.try_lock()
                {
                    /* we own HARDWARE and HARDWARE_PREV_OWNER so safe to say,
                    we can slap our ID on the owner and return the unlocked HARDWARE contents */
                    *owner_lock = Some(pcore::PhysicalCore::get_id());
                    return Some(lock);
                }

                /* this counts as an attempt */
                attempt = true;
            },

            /* couldn't obtain the hardware lock, so decide whether
            we rightfully own this lock, or need to wait for it to be released */
            None =>
            {
                match HARDWARE_PREV_OWNER.try_lock()
                {
                    /* we couldn't get HARDWARE but we did get HARDWARE_PREV_OWNER */
                    Some(owner_lock) => match *owner_lock
                    {
                        /* are we supposed to own HARDWARE? */
                        Some(owner) => if owner == pcore::PhysicalCore::get_id()
                        {
                            /* we own this HARDWARE lock -- probably held across an IRQ/exception --
                            so reclaim it while we still hold HARDWARE_PREV_OWNER */
                            unsafe { HARDWARE.force_unlock(); }
                            return Some(HARDWARE.lock());
                        },

                        /* not obtaining the hardware nor owner lock counts as an attempt */
                        None => attempt = true
                    },

                    /* failing to get the previous owner counts as an attempt */
                    None => attempt = true
                }
            }
        }

        match attempts_allowed
        {
            LockAttempts::Once => if attempt == true
            {
                /* one strike and you're out */
                return None;
            },
            LockAttempts::Multiple => ()
        }
    }
}

/* routines to interact with the system's base devices */

/* write the string msg out to the debug logging console.
   if the system is busy then return immediately, don't block.
   => msg = string to write out
   <= true if able to write, false if not */
pub fn write_debug_string(msg: &str) -> bool
{
    let hw = acquire_hardware_lock(LockAttempts::Once);
    if hw.is_none() == true
    {
        return false;
    }

    match &*(hw.unwrap())
    {
        Some(d) =>
        {
            d.write_debug_string(msg);
            true
        },
        None => false
    }
}

/* return number of discovered logical CPU cores, or None if value unavailable */
pub fn get_nr_cpu_cores() -> Option<usize>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => Some(d.get_nr_cpu_cores()),
        None => None
    }
}

/* return a list of the physical RAM chunks present in the system,
or None if we can't read the available memory */
pub fn get_phys_ram_chunks() -> Option<Vec<platform::physmem::RAMArea>>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => Some(d.get_phys_ram_areas()),
        None => None
    }
}

/* return total amount of physical RAM present in the system */
pub fn get_phys_ram_total() -> Option<usize>
{
    if let Some(areas) = get_phys_ram_chunks()
    {
        let mut total = 0;
        for area in areas
        {
            total = total + area.size;
        }

        return Some(total);
    }

    None
}

/* for this CPU core, enable scheduler timer interrupt */
pub fn scheduler_timer_start()
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_timer_start(),
        None => ()
    };
}

/* tell the scheduler to interrupt this core
when duration number of timer ticks or sub-seconds passes */
pub fn scheduler_timer_next_in(duration: timer::TimerValue)
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_timer_next_in(duration),
        None => ()
    };
}

/* tell the scheduler to interrupt this core when the system clock equals
target value in ticks or sub-seconds as its current value */
pub fn scheduler_timer_at(target: timer::TimerValue)
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_timer_at(target),
        None => ()
    };
}

/* get when the scheduler timer IRQ is next set to fire on this core.
this is a clock-on-the-wall value: it's a number of ticks or
sub-seconds since the timer started, not the duration to the next IRQ */
pub fn scheduler_get_timer_next_at() -> Option<timer::TimerValue>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_get_timer_next_at(),
        None => None
    }
}

/* get the CPU's timer frequency in Hz */
pub fn scheduler_get_timer_frequency() -> Option<u64>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_get_timer_frequency(),
        None => None
    }
}

/* return the timer's current value in microseconds, or None for no timer
this is a clock-on-the-wall value in that it always incremements and does
not reset. the underlying platform code can do what it needs to implement this */
pub fn scheduler_get_timer_now() -> Option<timer::TimerValue>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => d.scheduler_get_timer_now(),
        None => None
    }
}

/* clone the system's base device tree blob structure so it can be passed
to guest capsules. the platform code should customize the tree to ensure
peripherals are virtualized. the platform code therefore controls what
hardware is provided. the hypervisor sets how many CPUs and RAM are available.
the rest is decided by the platform code.
   => cpus = number of virtual CPU cores in this capsule
      boot_cpu_id = ID of system's boot CPU (typically 0)
      mem_base = base physical address of the contiguous system RAM
      mem_size = number of bytes available in the system RAM
   <= returns dtb as a byte array, or an error code
*/
pub fn clone_dtb_for_capsule(cpus: usize, boot_cpu_id: u32, mem_base: PhysMemBase, mem_size: PhysMemSize) -> Result<Vec<u8>, Cause>
{
    match &*(acquire_hardware_lock(LockAttempts::Multiple).unwrap())
    {
        Some(d) => match d.spawn_virtual_environment(cpus, boot_cpu_id, mem_base, mem_size)
        {
            Some(v) => return Ok(v),
            None => return Err(Cause::DeviceTreeBad)
        },
        None => Err(Cause::CantCloneDevices)
    }
}<commit_msg>Use built-in mutexes not spin-rs<commit_after>/* diosix abstracted hardware manager
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

use alloc::vec::Vec;
use super::lock::Mutex;
use platform::devices::Devices;
use platform::physmem::{PhysMemBase, PhysMemSize};
use platform::timer;
use super::error::Cause;

lazy_static!
{
    /* acquire HARDWARE before accessing any system hardware */
    static ref HARDWARE: Mutex<Option<Devices>> = Mutex::new(None);
}

/* parse_and_init
   Parse a device tree structure to create a base set of hardware devices.
   also initialize the devices so they can be used.
   call before using acquire_hardware_lock() to access HARDWARE.
   => device_tree = byte slice containing the device tree in physical memory
   <= return Ok for success, or error code on failure
*/
pub fn parse_and_init(dtb: &[u8]) -> Result<(), Cause>
{
    if let Ok(dt) = Devices::new(dtb)
    {
        *(HARDWARE.lock()) = Some(dt);
        return Ok(())
    }
    else
    {
        return Err(Cause::DeviceTreeBad);
    }
}

/* routines to interact with the system's base devices */

/* write the string msg out to the debug logging console.
   if the system is busy, return
   => msg = string to write out
   <= true if able to write, false if not */
pub fn write_debug_string(msg: &str) -> bool
{
    /* avoid blocking if we can */
    if HARDWARE.is_locked() == true
    {
        return false;
    }

    match &*(HARDWARE.lock())
    {
        Some(d) =>
        {
            d.write_debug_string(msg);
            true
        },
        None => false
    }
}

/* return number of discovered logical CPU cores, or None if value unavailable */
pub fn get_nr_cpu_cores() -> Option<usize>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => Some(d.get_nr_cpu_cores()),
        None => None
    }
}

/* return a list of the physical RAM chunks present in the system,
or None if we can't read the available memory */
pub fn get_phys_ram_chunks() -> Option<Vec<platform::physmem::RAMArea>>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => Some(d.get_phys_ram_areas()),
        None => None
    }
}

/* return total amount of physical RAM present in the system */
pub fn get_phys_ram_total() -> Option<usize>
{
    if let Some(areas) = get_phys_ram_chunks()
    {
        let mut total = 0;
        for area in areas
        {
            total = total + area.size;
        }

        return Some(total);
    }

    None
}

/* for this CPU core, enable scheduler timer interrupt */
pub fn scheduler_timer_start()
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_timer_start(),
        None => ()
    };
}

/* tell the scheduler to interrupt this core
when duration number of timer ticks or sub-seconds passes */
pub fn scheduler_timer_next_in(duration: timer::TimerValue)
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_timer_next_in(duration),
        None => ()
    };
}

/* tell the scheduler to interrupt this core when the system clock equals
target value in ticks or sub-seconds as its current value */
pub fn scheduler_timer_at(target: timer::TimerValue)
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_timer_at(target),
        None => ()
    };
}

/* get when the scheduler timer IRQ is next set to fire on this core.
this is a clock-on-the-wall value: it's a number of ticks or
sub-seconds since the timer started, not the duration to the next IRQ */
pub fn scheduler_get_timer_next_at() -> Option<timer::TimerValue>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_get_timer_next_at(),
        None => None
    }
}

/* get the CPU's timer frequency in Hz */
pub fn scheduler_get_timer_frequency() -> Option<u64>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_get_timer_frequency(),
        None => None
    }
}

/* return the timer's current value in microseconds, or None for no timer
this is a clock-on-the-wall value in that it always incremements and does
not reset. the underlying platform code can do what it needs to implement this */
pub fn scheduler_get_timer_now() -> Option<timer::TimerValue>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => d.scheduler_get_timer_now(),
        None => None
    }
}

/* clone the system's base device tree blob structure so it can be passed
to guest capsules. the platform code should customize the tree to ensure
peripherals are virtualized. the platform code therefore controls what
hardware is provided. the hypervisor sets how many CPUs and RAM are available.
the rest is decided by the platform code.
   => cpus = number of virtual CPU cores in this capsule
      boot_cpu_id = ID of system's boot CPU (typically 0)
      mem_base = base physical address of the contiguous system RAM
      mem_size = number of bytes available in the system RAM
   <= returns dtb as a byte array, or an error code
*/
pub fn clone_dtb_for_capsule(cpus: usize, boot_cpu_id: u32, mem_base: PhysMemBase, mem_size: PhysMemSize) -> Result<Vec<u8>, Cause>
{
    match &*(HARDWARE.lock())
    {
        Some(d) => match d.spawn_virtual_environment(cpus, boot_cpu_id, mem_base, mem_size)
        {
            Some(v) => return Ok(v),
            None => return Err(Cause::DeviceTreeBad)
        },
        None => Err(Cause::CantCloneDevices)
    }
}<|endoftext|>


<commit_before>use util::flat_tree::FlatTree;
use util::flat_tree::TreeNode;
use std::ops::Deref;
use super::LayoutBox;
use markup::Node;
use state::StateBuffer;

mod repeat_node;
mod simple_node;

pub struct LayoutBuffer(FlatTree<LayoutBox>);
pub type LayoutNode = TreeNode<LayoutBox>;

impl Deref for LayoutBuffer {
    type Target = [LayoutNode];

    fn deref<'a>(&'a self) -> &'a [LayoutNode] {
        self.0.deref()
    }
}

impl LayoutBuffer {

    pub fn new(style_tree: &Node) -> LayoutBuffer {

        let size = style_tree.tree_size();

        LayoutBuffer(FlatTree::new(style_tree, size, converter))
    }

    pub fn update_from_state(&mut self, state_buffer: &StateBuffer) {

        for (lb, state) in self.0.iter_mut().zip(state_buffer.iter()) {
            lb.update_from_state(state);
        }
    }

    pub fn compute_layout(&mut self, max_width: f32, max_height: f32) {

        // First pass: compute default width
        for root in self.0.tree_iter_mut() {
            compute_layout_defaut_width(root, max_width);
        }

        // Second pass: compute auto margins and width auto
        for root in self.0.tree_iter_mut() {
            compute_layout_auto_width(root, max_width);
        }

        // Third pass: layout children and compute their height
        for root in self.0.tree_iter_mut() {
            compute_layout_height_and_position(root, max_height);
        }
    }
}

fn converter(_: &Node) -> Option<LayoutBox> {
    Some(LayoutBox::default())
}

/// This function compute the width for this node
/// and return the space it would have eaten if it had more space
/// than the one given.
///
/// This can appear when this node has a child with a fixed width.
fn compute_layout_defaut_width(this: &mut LayoutNode, space_available_for_self: f32) -> f32
{
    // Compute the extra part to remove
    let o = this.dim.padding.left
        + this.dim.padding.right
        + this.dim.margin.left
        + this.dim.margin.right
        + this.dim.border.left
        + this.dim.border.right;

    // Compute the space available for each line
    let space_available = if this.flags.has_width_fixed() {
        this.dim.content.width
    } else {
        space_available_for_self - o
    };

    // Iterating variables
    let mut max = 0f32;
    let mut sum = 0f32;
    let mut line_space_available = space_available;

    // Scope to reduce iter lifetime.
    {
        let mut iter = this.children_mut();
        let mut option_next = iter.next();
        let mut next_child = false;

        loop {

            // This line is confusing...
            // child has the type &mut &mut LayoutBox (one additional indirection)
            // but in release both child, option_next and iter are optimized out.
            // So I guess I shouldn't worry about that, or not ?
            if let Some(ref mut child) = option_next {

                // Recursive call: eat the space given
                let space_eaten = compute_layout_defaut_width(child, line_space_available);

                // If the child has not eaten more than given
                // then we just reduce the space available for the next child
                if line_space_available >= space_eaten {

                    line_space_available -= space_eaten;
                    sum += space_eaten;

                    // Should we increase the max line size ?
                    if sum > max {
                        max = sum;
                    }

                    // If the child is auto then we simply restart with a new line
                    if child.flags.is_new_line_forced() {
                        sum = 0f32;
                        line_space_available = space_available;
                    }

                    // We'll go see for the next child now.
                    next_child = true;

                // Otherwise, we have to put the child on a new line
                // except if the child was alone on its line
                } else {

                    // Am I alone ?
                    if line_space_available == space_available {

                        // This might be surprising, but here we want to
                        // transmit back to our parent the child constraint.
                        if sum > max {
                            max = sum;
                        }

                        next_child = true;

                    // If I wasn't alone, as I will be on a new line,
                    // the recursion will be done again. This do have an overhead.
                    }

                    // Then start a new line:
                    sum = 0f32;
                    line_space_available = space_available;
                }

            } else {
                break;
            }

            if next_child {

                // Go take care of the next child:
                option_next = iter.next();

                next_child = false;
            }
        }
    }

    // Assign width for this.
    if !this.flags.has_width_fixed() {
        this.dim.content.width = if this.flags.has_width_expand() {
            space_available
        } else {
            max.min(space_available)
        }
    };

    // Compute the free space for margin in expand mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_expand(), this.flags.has_margin_left_expand()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }

    if this.flags.has_width_fixed() {
        this.dim.content.width + o
    } else {
        max + o
    }
}

/// This function performs a tree traversal to compute the auto values
/// on nodes in the tree.
/// It should be called after compute_layout_default_width
fn compute_layout_auto_width(this: &mut LayoutNode, space_available: f32)
{
    for child in this.children_mut() {

        compute_layout_auto_width(child, this.dim.content.width);
    }

    // Resolve auto width for this.
    if this.flags.has_width_auto() {
        let o = this.dim.padding.left
            + this.dim.padding.right
            + this.dim.margin.left
            + this.dim.margin.right
            + this.dim.border.left
            + this.dim.border.right;

        this.dim.content.width = space_available - o;
    }

    // Compute the free space for margin in auto mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_auto(), this.flags.has_margin_left_auto()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }
}

//
// TODO: FIXME Text nodes must have their size precomputed somehow
//
// PRECONDITONS: compute_width has been called
//
fn compute_layout_height_and_position(this: &mut LayoutNode, max_height: f32)
{

    // At this point we don't know this.dim.height / this.dim.width
    // positions
    let mut x = this.dim.content.x
        + this.dim.padding.left
        + this.dim.margin.left
        + this.dim.border.left;
    let mut y = this.dim.content.y
        + this.dim.padding.top
        + this.dim.margin.top
        + this.dim.border.top;

    // Equivalent rule for child max height:
    let child_max_height = if this.flags.has_height_fixed() {

        this.dim.content.height
    } else {

        max_height
        - this.dim.padding.bottom - this.dim.padding.top
        - this.dim.border.bottom  - this.dim.border.top
        - this.dim.margin.bottom  - this.dim.margin.top
    };

    // Current line width allow to track the layout progress
    // in the x direction while height allow to track the y direction
    let mut current_line_width  = 0f32;
    let mut current_line_height = 0f32;
    let mut current_height_left = child_max_height;
    let mut accumulated_line_height = 0f32;

    // Reduced scope for stack (borrowck problem otherwise)
    {
        // Used for margin (top/bottom)
        let mut stack: Vec<&mut LayoutNode> = Vec::with_capacity(4);

        macro_rules! resolve_top_bot_auto_margins {
            ($stack:ident,
             $current_line_height:ident) => ({

                 while let Some(ref mut c) = $stack.pop() {

                     let s = $current_line_height - c.dim.content.height
                         - c.dim.padding.top - c.dim.padding.bottom
                         - c.dim.border.top  - c.dim.border.bottom
                         - c.dim.margin.top  - c.dim.margin.bottom;

                     // We compute the margin top / bottom
                     match (c.flags.has_margin_top_auto(), c.flags.has_margin_bottom_auto()) {
                         (true, true) => {
                             c.dim.margin.top    = s / 2f32;
                             c.dim.margin.bottom = s / 2f32;
                         }
                         (true, false) => {
                             c.dim.margin.top   = s;
                         }
                         (false, true) => {
                             c.dim.margin.bottom  = s;
                         }
                         _ => ()
                     }
                 }
            })
        }

        macro_rules! line_return {

            ($stack:ident,
             $current_line_height:ident,
             $current_line_width:ident,
             $current_height_left:ident,
             $accumulated_line_height:ident,
             $d:ident) => ({

                resolve_top_bot_auto_margins!($stack, $current_line_height);

                x = $d.content.x + $d.padding.left + $d.border.left + $d.margin.left;
                y += $current_line_height;
                $accumulated_line_height += $current_line_height;
                $current_height_left     -= $current_line_height;
                $current_line_width   = 0f32;
                $current_line_height  = 0f32;
            });
        }

        for child in this.children_mut() {

            let need_new_line = child.flags.is_new_line_forced();

            // Line return ?
            if child.dim.content.width + current_line_width > this.dim.content.width {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }

            child.dim.content.x = x;
            child.dim.content.y = y;

            // Update the x position:
            let child_total_width = child.dim.content.width
                + child.dim.margin.left
                + child.dim.margin.right
                + child.dim.border.left
                + child.dim.border.right;

            x += child_total_width;
            current_line_width += child_total_width;

            compute_layout_height_and_position(child, current_height_left);

            // Note: at this point child.margin (top, right) are either fixed
            // or zero (if they were auto). They will be computed in a later pass.
            current_line_height = current_line_height.max(child.dim.content.height
                + child.dim.margin.top
                + child.dim.margin.bottom
                + child.dim.border.top
                + child.dim.border.bottom
            );

            if child.flags.has_margin_top_or_bot_auto() {
                stack.push(child);
            }

            if need_new_line {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }
        }

        // Last line: we end the line and
        // update margin top/bot auto if needed.
        resolve_top_bot_auto_margins!(stack, current_line_height);
        accumulated_line_height += current_line_height;
    }

    // Finally: the height !
    this.dim.content.height =
        this.dim.content.height.max(child_max_height.min(accumulated_line_height));
}
<commit_msg>Fixed margin expand bug and incorrect width values.<commit_after>use util::flat_tree::FlatTree;
use util::flat_tree::TreeNode;
use std::ops::Deref;
use super::LayoutBox;
use markup::Node;
use state::StateBuffer;

mod repeat_node;
mod simple_node;

pub struct LayoutBuffer(FlatTree<LayoutBox>);
pub type LayoutNode = TreeNode<LayoutBox>;

impl Deref for LayoutBuffer {
    type Target = [LayoutNode];

    fn deref<'a>(&'a self) -> &'a [LayoutNode] {
        self.0.deref()
    }
}

impl LayoutBuffer {

    pub fn new(style_tree: &Node) -> LayoutBuffer {

        let size = style_tree.tree_size();

        LayoutBuffer(FlatTree::new(style_tree, size, converter))
    }

    pub fn update_from_state(&mut self, state_buffer: &StateBuffer) {

        for (lb, state) in self.0.iter_mut().zip(state_buffer.iter()) {
            lb.update_from_state(state);
        }
    }

    pub fn compute_layout(&mut self, max_width: f32, max_height: f32) {

        // First pass: compute default width
        for root in self.0.tree_iter_mut() {
            compute_layout_defaut_width(root, max_width);
        }

        // Second pass: compute auto margins and width auto
        for root in self.0.tree_iter_mut() {
            compute_layout_auto_width(root, max_width);
        }

        // Third pass: layout children and compute their height
        for root in self.0.tree_iter_mut() {
            compute_layout_height_and_position(root, max_height);
        }
    }
}

fn converter(_: &Node) -> Option<LayoutBox> {
    Some(LayoutBox::default())
}

/// This function compute the width for this node
/// and return the space it would have eaten if it had more space
/// than the one given.
///
/// This can appear when this node has a child with a fixed width.
fn compute_layout_defaut_width(this: &mut LayoutNode, space_available_for_self: f32) -> f32
{
    // Compute the extra part to remove
    let mut o = this.dim.padding.left
        + this.dim.padding.right
        + this.dim.margin.left
        + this.dim.margin.right
        + this.dim.border.left
        + this.dim.border.right;

    // Compute the space available for each line
    let space_available = if this.flags.has_width_fixed() {
        this.dim.content.width
    } else {
        space_available_for_self - o
    };

    // Iterating variables
    let mut max = 0f32;
    let mut sum = 0f32;
    let mut line_space_available = space_available;

    // Scope to reduce iter lifetime.
    {
        let mut iter = this.children_mut();
        let mut option_next = iter.next();
        let mut next_child = false;

        loop {

            // This line is confusing...
            // child has the type &mut &mut LayoutBox (one additional indirection)
            // but in release both child, option_next and iter are optimized out.
            // So I guess I shouldn't worry about that, or not ?
            if let Some(ref mut child) = option_next {

                // Recursive call: eat the space given
                let space_eaten = compute_layout_defaut_width(child, line_space_available);

                // If the child has not eaten more than given
                // then we just reduce the space available for the next child
                if line_space_available >= space_eaten {

                    line_space_available -= space_eaten;
                    sum += space_eaten;

                    // Should we increase the max line size ?
                    if sum > max {
                        max = sum;
                    }

                    // If the child is auto then we simply restart with a new line
                    if child.flags.is_new_line_forced() {
                        sum = 0f32;
                        line_space_available = space_available;
                    }

                    // We'll go see for the next child now.
                    next_child = true;

                // Otherwise, we have to put the child on a new line
                // except if the child was alone on its line
                } else {

                    // Am I alone ?
                    if line_space_available == space_available {

                        // This might be surprising, but here we want to
                        // propagate back through the parent hiearchy the child constraint.
                        sum += space_eaten;
                        if sum > max {
                            max = sum;
                        }

                        next_child = true;

                    // If I wasn't alone, as I will be on a new line,
                    // the recursion will be done again. This do have an overhead.
                    }

                    // Then start a new line:
                    sum = 0f32;
                    line_space_available = space_available;
                }

            } else {
                break;
            }

            if next_child {

                // Go take care of the next child:
                option_next = iter.next();

                next_child = false;
            }
        }
    }

    // Assign width for this.
    if !this.flags.has_width_fixed() {
        this.dim.content.width = if this.flags.has_width_expand() {
            space_available
        } else {
            max.min(space_available)
        }
    };

    // Compute the free space for margin in expand mode:
    let s = space_available_for_self - o - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_expand(), this.flags.has_margin_left_expand()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
            o += s;
        }
        (true, false) => {
            this.dim.margin.left = s;
            o += s;
        }
        (false, true) => {
            this.dim.margin.right = s;
            o += s;
        }
        _ => ()
    }

    if this.flags.has_width_fixed() {
        this.dim.content.width + o
    } else {
        max + o
    }
}

/// This function performs a tree traversal to compute the auto values
/// on nodes in the tree.
/// It should be called after compute_layout_default_width
fn compute_layout_auto_width(this: &mut LayoutNode, space_available: f32)
{
    // Resolve auto width for this.
    if this.flags.has_width_auto() {
        let o = this.dim.padding.left
            + this.dim.padding.right
            + this.dim.margin.left
            + this.dim.margin.right
            + this.dim.border.left
            + this.dim.border.right;

        this.dim.content.width = space_available - o;
    }

    for child in this.children_mut() {

        compute_layout_auto_width(child, this.dim.content.width);
    }

    // Compute the free space for margin in auto mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_auto(), this.flags.has_margin_left_auto()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }
}

//
// TODO: FIXME Text nodes must have their size precomputed somehow
//
// PRECONDITONS: compute_width has been called
//
fn compute_layout_height_and_position(this: &mut LayoutNode, max_height: f32)
{

    // At this point we don't know this.dim.height / this.dim.width
    // positions
    let mut x = this.dim.content.x
        + this.dim.padding.left
        + this.dim.margin.left
        + this.dim.border.left;
    let mut y = this.dim.content.y
        + this.dim.padding.top
        + this.dim.margin.top
        + this.dim.border.top;

    // Equivalent rule for child max height:
    let child_max_height = if this.flags.has_height_fixed() {

        this.dim.content.height
    } else {

        max_height
        - this.dim.padding.bottom - this.dim.padding.top
        - this.dim.border.bottom  - this.dim.border.top
        - this.dim.margin.bottom  - this.dim.margin.top
    };

    // Current line width allow to track the layout progress
    // in the x direction while height allow to track the y direction
    let mut current_line_width  = 0f32;
    let mut current_line_height = 0f32;
    let mut current_height_left = child_max_height;
    let mut accumulated_line_height = 0f32;

    // Reduced scope for stack (borrowck problem otherwise)
    {
        // Used for margin (top/bottom)
        let mut stack: Vec<&mut LayoutNode> = Vec::with_capacity(4);

        macro_rules! resolve_top_bot_auto_margins {
            ($stack:ident,
             $current_line_height:ident) => ({

                 while let Some(ref mut c) = $stack.pop() {

                     let s = $current_line_height - c.dim.content.height
                         - c.dim.padding.top - c.dim.padding.bottom
                         - c.dim.border.top  - c.dim.border.bottom
                         - c.dim.margin.top  - c.dim.margin.bottom;

                     // We compute the margin top / bottom
                     match (c.flags.has_margin_top_auto(), c.flags.has_margin_bottom_auto()) {
                         (true, true) => {
                             c.dim.margin.top    = s / 2f32;
                             c.dim.margin.bottom = s / 2f32;
                         }
                         (true, false) => {
                             c.dim.margin.top   = s;
                         }
                         (false, true) => {
                             c.dim.margin.bottom  = s;
                         }
                         _ => ()
                     }
                 }
            })
        }

        macro_rules! line_return {

            ($stack:ident,
             $current_line_height:ident,
             $current_line_width:ident,
             $current_height_left:ident,
             $accumulated_line_height:ident,
             $d:ident) => ({

                resolve_top_bot_auto_margins!($stack, $current_line_height);

                x = $d.content.x + $d.padding.left + $d.border.left + $d.margin.left;
                y += $current_line_height;
                $accumulated_line_height += $current_line_height;
                $current_height_left     -= $current_line_height;
                $current_line_width   = 0f32;
                $current_line_height  = 0f32;
            });
        }

        for child in this.children_mut() {

            let need_new_line = child.flags.is_new_line_forced();

            // Line return ?
            if child.dim.content.width + current_line_width > this.dim.content.width {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }

            child.dim.content.x = x;
            child.dim.content.y = y;

            // Update the x position:
            let child_total_width = child.dim.content.width
                + child.dim.margin.left
                + child.dim.margin.right
                + child.dim.border.left
                + child.dim.border.right;

            x += child_total_width;
            current_line_width += child_total_width;

            compute_layout_height_and_position(child, current_height_left);

            // Note: at this point child.margin (top, right) are either fixed
            // or zero (if they were auto). They will be computed in a later pass.
            current_line_height = current_line_height.max(child.dim.content.height
                + child.dim.margin.top
                + child.dim.margin.bottom
                + child.dim.border.top
                + child.dim.border.bottom
            );

            if child.flags.has_margin_top_or_bot_auto() {
                stack.push(child);
            }

            if need_new_line {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }
        }

        // Last line: we end the line and
        // update margin top/bot auto if needed.
        resolve_top_bot_auto_margins!(stack, current_line_height);
        accumulated_line_height += current_line_height;
    }

    // Finally: the height !
    this.dim.content.height =
        this.dim.content.height.max(child_max_height.min(accumulated_line_height));
}
<|endoftext|>


<commit_before>use super::{super::completer::*, InteractiveBinary};
use crate::{sys, types};
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(binary: &InteractiveBinary) -> Option<String> {
    let prompt = binary.prompt();
    let line =
        binary.context.borrow_mut().read_line(prompt, None, &mut |Event { editor, kind }| {
            let shell = binary.shell.borrow();
            let dirs = &shell.directory_stack;
            let prev = &shell.variables.get::<types::Str>("OLDPWD");
            let vars = &shell.variables;

            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => words
                        .into_iter()
                        .nth(index)
                        .map(|(start, end)| editor.current_buffer().range(start, end))
                        .and_then(|filename| {
                            Some(complete_as_file(&env::current_dir().ok()?, &filename, index))
                        })
                        .filter(|&x| x)
                        .is_some(),
                };

                let dir_completer =
                    IonFileCompleter::new(None, dirs, prev.as_ref().map(types::Str::as_str));

                if filename {
                    mem::replace(&mut editor.context().completer, Some(Box::new(dir_completer)));
                } else {
                    // Initialize a new completer from the definitions collected.
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let custom_completer = BasicCompleter::new(
                        shell
                            .builtins()
                            .keys()
                            // Add built-in commands to the completer's definitions.
                            .map(ToString::to_string)
                            // Add the history list to the completer's definitions.
                            // Map each underlying `liner::Buffer` into a `String`.
                            .chain(editor.context().history.buffers.iter().map(ToString::to_string))
                            // Add the aliases to the completer's definitions.
                            .chain(vars.aliases().map(|(key, _)| key.to_string()))
                            // Add the list of available functions to the completer's
                            // definitions.
                            .chain(vars.functions().map(|(key, _)| key.to_string()))
                            // Add the list of available variables to the completer's
                            // definitions. TODO: We should make
                            // it free to do String->SmallString
                            //       and mostly free to go back (free if allocated)
                            .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                            .collect(),
                    );

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| {
                            IonFileCompleter::new(
                                Some(s),
                                dirs,
                                prev.as_ref().map(types::Str::as_str),
                            )
                        })
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    file_completers.push(dir_completer);

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        });

    match line {
        Ok(line) => {
            if line.bytes().next() != Some(b'#') && line.bytes().any(|c| !c.is_ascii_whitespace()) {
                binary.shell.borrow_mut().unterminated = true;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            if binary.shell.borrow_mut().flow_control.pop() {
                None
            } else {
                let status = binary.shell.borrow().previous_status;
                binary.shell.borrow_mut().exit(status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<commit_msg>Don't exit a blockquote if Ctrl-D is pressed in a multiline statement<commit_after>use super::{super::completer::*, InteractiveBinary};
use crate::{sys, types};
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(binary: &InteractiveBinary) -> Option<String> {
    let prompt = binary.prompt();
    let line =
        binary.context.borrow_mut().read_line(prompt, None, &mut |Event { editor, kind }| {
            let shell = binary.shell.borrow();
            let dirs = &shell.directory_stack;
            let prev = &shell.variables.get::<types::Str>("OLDPWD");
            let vars = &shell.variables;

            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => words
                        .into_iter()
                        .nth(index)
                        .map(|(start, end)| editor.current_buffer().range(start, end))
                        .and_then(|filename| {
                            Some(complete_as_file(&env::current_dir().ok()?, &filename, index))
                        })
                        .filter(|&x| x)
                        .is_some(),
                };

                let dir_completer =
                    IonFileCompleter::new(None, dirs, prev.as_ref().map(types::Str::as_str));

                if filename {
                    mem::replace(&mut editor.context().completer, Some(Box::new(dir_completer)));
                } else {
                    // Initialize a new completer from the definitions collected.
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let custom_completer = BasicCompleter::new(
                        shell
                            .builtins()
                            .keys()
                            // Add built-in commands to the completer's definitions.
                            .map(ToString::to_string)
                            // Add the history list to the completer's definitions.
                            // Map each underlying `liner::Buffer` into a `String`.
                            .chain(editor.context().history.buffers.iter().map(ToString::to_string))
                            // Add the aliases to the completer's definitions.
                            .chain(vars.aliases().map(|(key, _)| key.to_string()))
                            // Add the list of available functions to the completer's
                            // definitions.
                            .chain(vars.functions().map(|(key, _)| key.to_string()))
                            // Add the list of available variables to the completer's
                            // definitions. TODO: We should make
                            // it free to do String->SmallString
                            //       and mostly free to go back (free if allocated)
                            .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                            .collect(),
                    );

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| {
                            IonFileCompleter::new(
                                Some(s),
                                dirs,
                                prev.as_ref().map(types::Str::as_str),
                            )
                        })
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    file_completers.push(dir_completer);

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        });

    match line {
        Ok(line) => {
            if line.bytes().next() != Some(b'#') && line.bytes().any(|c| !c.is_ascii_whitespace()) {
                binary.shell.borrow_mut().unterminated = true;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            let mut shell = binary.shell.borrow_mut();
            if shell.unterminated {
                None
            } else if shell.flow_control.pop() {
                None
            } else {
                let status = shell.previous_status;
                shell.exit(status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<|endoftext|>