<commit_before>use super::scheduler::*;

use std::sync::Arc;

///
/// A data storage structure used to govern synchronous and asynchronous access to an underlying object.
///
pub struct Desync<T: Send> {
    /// Queue used for scheduling runtime for this object
    queue:  Arc<JobQueue>,

    /// Data for this object. Boxed so the pointer remains the same through the lifetime of the object.
    data:   Box<T>
}

// Rust actually derives this anyway at the moment
unsafe impl<T: Send> Send for Desync<T> {}

// True iff queue: Sync
unsafe impl<T: Send> Sync for Desync<T> {}

///
/// Used for passing the data pointer through to the queue
///
/// 'Safe' because the queue is synchronised during drop, so we can never use the pointer
/// if the object does not exist.
///
struct DataRef<T: Send>(*const T);
unsafe impl<T: Send> Send for DataRef<T> {}

// TODO: we can change DataRef to Shared (https://doc.rust-lang.org/std/ptr/struct.Shared.html in the future)

// TODO: T does not need to be static as we know that its lifetime is at least the lifetime of Desync<T> and hence the queue
impl<T: 'static+Send> Desync<T> {
    ///
    /// Creates a new Desync object
    ///
    pub fn new(data: T) -> Desync<T> {
        let queue = queue();

        Desync {
            queue:  queue,
            data:   Box::new(data)
        }
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    pub fn async<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where
            let data = DataRef(&*self.data);

            async(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data);
            })
        }
    }

    ///
    /// Performs an operation synchronously on this item. This will be queued with any other
    /// jobs that this item may be performing, and this function will not return until the
    /// job is complete and the result is available.
    ///
    pub fn sync<TFn, Result>(&self, job: TFn) -> Result
    where TFn: 'static+Send+FnOnce(&mut T) -> Result, Result: 'static+Send {
        let result = unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where
            let data = DataRef(&*self.data);

            sync(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data)
            })
        };

        result
    }
}

impl<T: Send> Drop for Desync<T> {
    fn drop(&mut self) {
        // Ensure that everything on the queue has committed by queueing a last synchronous event
        // (Not synchronising the queue would make this unsafe as we would hold on to a pointer to
        // the internal data structure)
        sync(&self.queue, || {});
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread::*;
    use std::time::*;

    struct TestData {
        val: u32
    }

    #[test]
    fn can_retrieve_data_synchronously() {
        let desynced = Desync::new(TestData { val: 0 });

        assert!(desynced.sync(|data| data.val) == 0);
    }

    #[test]
    fn can_update_data_asynchronously() {
        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        assert!(desynced.sync(|data| data.val) == 42);
    }

    #[test]
    fn dropping_while_running_isnt_obviously_bad() {
        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });
        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });
    }
}
<commit_msg>Add support for futures to the main Desync object too<commit_after>use super::scheduler::*;

use std::sync::Arc;
use futures::sync::oneshot;
use futures::future::Future;

///
/// A data storage structure used to govern synchronous and asynchronous access to an underlying object.
///
pub struct Desync<T: Send> {
    /// Queue used for scheduling runtime for this object
    queue:  Arc<JobQueue>,

    /// Data for this object. Boxed so the pointer remains the same through the lifetime of the object.
    data:   Box<T>
}

// Rust actually derives this anyway at the moment
unsafe impl<T: Send> Send for Desync<T> {}

// True iff queue: Sync
unsafe impl<T: Send> Sync for Desync<T> {}

///
/// Used for passing the data pointer through to the queue
///
/// 'Safe' because the queue is synchronised during drop, so we can never use the pointer
/// if the object does not exist.
///
struct DataRef<T: Send>(*const T);
unsafe impl<T: Send> Send for DataRef<T> {}

// TODO: we can change DataRef to Shared (https://doc.rust-lang.org/std/ptr/struct.Shared.html in the future)

// TODO: T does not need to be static as we know that its lifetime is at least the lifetime of Desync<T> and hence the queue
impl<T: 'static+Send> Desync<T> {
    ///
    /// Creates a new Desync object
    ///
    pub fn new(data: T) -> Desync<T> {
        let queue = queue();

        Desync {
            queue:  queue,
            data:   Box::new(data)
        }
    }

    ///
    /// Performs an operation asynchronously on this item. This function will return
    /// immediately and the job will happen on a separate thread at some time in the
    /// future (generally fairly soon).
    ///
    /// Jobs are always performed in the order that they are queued and are always
    /// performed synchronously with respect to this object.
    ///
    pub fn async<TFn>(&self, job: TFn)
    where TFn: 'static+Send+FnOnce(&mut T) -> () {
        unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where
            let data = DataRef(&*self.data);

            async(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data);
            })
        }
    }

    ///
    /// Performs an operation synchronously on this item. This will be queued with any other
    /// jobs that this item may be performing, and this function will not return until the
    /// job is complete and the result is available.
    ///
    pub fn sync<TFn, Result>(&self, job: TFn) -> Result
    where TFn: 'static+Send+FnOnce(&mut T) -> Result, Result: 'static+Send {
        let result = unsafe {
            // As drop() is the last thing called, we know that this object will still exist at the point where
            let data = DataRef(&*self.data);

            sync(&self.queue, move || {
                let data = data.0 as *mut T;
                job(&mut *data)
            })
        };

        result
    }

    ///
    /// Performs an operation asynchronously on this thread, returning the result via a future.
    ///
    pub fn future<TFn, Item: 'static+Send>(&self, job: TFn) -> Box<Future<Item=Item, Error=oneshot::Canceled>>
    where TFn: 'static+Send+FnOnce(&mut T) -> Item {
        let (send, receive) = oneshot::channel();

        self.async(|data| {
            let result = job(data);
            send.send(result).ok();
        });

        Box::new(receive)
    }
}

impl<T: Send> Drop for Desync<T> {
    fn drop(&mut self) {
        // Ensure that everything on the queue has committed by queueing a last synchronous event
        // (Not synchronising the queue would make this unsafe as we would hold on to a pointer to
        // the internal data structure)
        sync(&self.queue, || {});
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread::*;
    use std::time::*;

    struct TestData {
        val: u32
    }

    #[test]
    fn can_retrieve_data_synchronously() {
        let desynced = Desync::new(TestData { val: 0 });

        assert!(desynced.sync(|data| data.val) == 0);
    }

    #[test]
    fn can_update_data_asynchronously() {
        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        assert!(desynced.sync(|data| data.val) == 42);
    }

    #[test]
    fn can_update_data_with_future() {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        let mut future = executor::spawn(desynced.future(|data| data.val));

        assert!(future.wait_future().unwrap() == 42);
    }

    #[test]
    fn dropping_while_running_isnt_obviously_bad() {
        let desynced = Desync::new(TestData { val: 0 });

        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });
        desynced.async(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });
    }
}
<|endoftext|>


<commit_before>extern crate arrayvec;
extern crate decorum;
extern crate nalgebra;
extern crate plexus;

use decorum::R64;
use nalgebra::Point2;
use plexus::geometry::convert::AsPosition;
use plexus::geometry::Geometry;
use plexus::graph::geometry::alias::VertexPosition;
use plexus::graph::geometry::EdgeMidpoint;
use plexus::graph::{EdgeView, FaceView, GraphError, MeshGraph};
use plexus::prelude::*;

pub fn subdivide_triangular_face<G>(face: FaceView<&mut MeshGraph<G>, G>) -> Result<(), GraphError>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    // Bail if the face is not triangular.
    let arity = face.arity();
    if arity != 3 {
        return Err(GraphError::ArityConflict {
            expected: 3,
            actual: arity,
        });
    }
    // Split each edge, stashing the vertex key and moving to the next edge.
    let split = |edge: EdgeView<_, G>| -> Result<_, GraphError> {
        let vertex = edge.split()?;
        let x = vertex.key();
        Ok((x, vertex.into_outgoing_edge().into_next_edge()))
    };
    let (a, edge) = split(face.into_edge())?;
    let (b, edge) = split(edge)?;
    let (c, edge) = split(edge)?;
    // Bisect along the vertices from each edge split.
    edge.into_face()
        .unwrap()
        .bisect(a, b)?
        .into_face()
        .unwrap()
        .bisect(b, c)?
        .into_face()
        .unwrap()
        .bisect(c, a)
        .map(|_| ())
}

fn main() {
    // Create a graph from a right triangle.
    let mut graph = MeshGraph::<Point2<R64>>::from_raw_buffers_with_arity(
        vec![0u32, 1, 2],
        vec![(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)],
        3,
    )
    .unwrap();
    // Get the key of the singular face.
    let abc = graph.faces().nth(0).unwrap().key();
    // Subdivide the face.
    subdivide_triangular_face(graph.face_mut(abc).unwrap()).unwrap();
}
<commit_msg>Generalize split-based subdivisions.<commit_after>extern crate arrayvec;
extern crate decorum;
extern crate nalgebra;
extern crate plexus;

use decorum::R64;
use nalgebra::Point2;
use plexus::geometry::convert::AsPosition;
use plexus::geometry::Geometry;
use plexus::graph::geometry::alias::VertexPosition;
use plexus::graph::geometry::EdgeMidpoint;
use plexus::graph::{FaceView, GraphError, MeshGraph};
use plexus::prelude::*;

pub fn subdivide<G>(
    face: FaceView<&mut MeshGraph<G>, G>,
) -> Result<FaceView<&mut MeshGraph<G>, G>, GraphError>
where
    G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
    G::Vertex: AsPosition,
{
    // Split each edge, stashing the vertex key and moving to the next edge.
    let arity = face.arity();
    let mut edge = face.into_edge();
    let mut splits = Vec::with_capacity(arity);
    for _ in 0..arity {
        let vertex = edge.split()?;
        splits.push(vertex.key());
        edge = vertex.into_outgoing_edge().into_next_edge();
    }
    // Bisect along the vertices from each edge split.
    let mut face = edge.into_face().unwrap();
    for (a, b) in splits.into_iter().perimeter() {
        face = face.bisect(a, b)?.into_face().unwrap();
    }
    // Return the central face of the subdivision.
    Ok(face)
}

fn main() {
    // Create a graph from a right triangle.
    let mut graph = MeshGraph::<Point2<R64>>::from_raw_buffers_with_arity(
        vec![0u32, 1, 2],
        vec![(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)],
        3,
    )
    .unwrap();
    // Get the key of the singular face.
    let abc = graph.faces().nth(0).unwrap().key();
    // Subdivide the face.
    subdivide(graph.face_mut(abc).unwrap()).unwrap();
}
<|endoftext|>


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

fn main() {
    const X: u8 = 0;
    match 0u8 {
        X => { },
        b'\t' => { },
        1u8 => { },
        _ => { },
    }
}
<commit_msg>test: Add an assertion to the #16745 testcase<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
    const X: u8 = 0;
    let out: u8 = match 0u8 {
        X => 99,
        b'\t' => 1,
        1u8 => 2,
        _ => 3,
    };
    assert_eq!(out, 99);
}
<|endoftext|>


<commit_before>// Tests that "loop unsafe" isn't misparsed.

fn main() {
    loop unsafe {
        io::println("Hello world!");
    }
}

<commit_msg>Make test suite terminate.<commit_after>// Tests that "loop unsafe" isn't misparsed.

fn main() {
    loop unsafe {
        io::println("Hello world!");
        return ();
    }
}

<|endoftext|>


<commit_before>use std::convert;
use std::ops::{Add, Sub};
use internals::Node;

/// The class of monoids
///
/// The class of monoids (types with an sumiative binary operation that has
/// an identity).
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.sum(`_M_`::identity())` = _x_
///  + _M_`::identity().sum(`_x_`)` = _x_
///  + _x_`.sum(`_y_`.sum(`_z_`))` = _z_`.sum(`_x_`.sum(`_y_`))`
///  + _M_`::concat(`_a_`)` = _a_`.fold(`_M_`::identity,`_M_`::sum)`
///
pub trait Monoid: Sized {
    /// The identity operation of the monoid
    //  TODO: can this be represented by std::default::Default instead?
    fn identity() -> Self;

    /// The sum operation of the monoid
    //  TODO: can this be represented by std::ops::Add instead?
    fn sum(self, other: Self) -> Self;

    #[inline]
    fn concat<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::identity(), Self::sum)
    }
}

/// A monoid that can be applied to a `Node` as a measurement
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                              + Sub<usize, Output=Self>
                              + Sized {
    /// Apply this `Metric` to the given `Node`
    fn measure(node: &Node) -> Self;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index(&self, node: &Node) -> Option<usize>;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline] fn next(self, node: &Node) -> Option<usize> {
        (self + 1).to_byte_index(node)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline] fn back(self, node: &Node) -> Option<usize> {
        (self - 1).to_byte_index(node)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    // TODO: should this be a method on `Node`s instead?
    fn is_boundary(node: &Node, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(usize);
impl Monoid for Grapheme {
    #[inline] fn identity() -> Self { Grapheme(0) }
    #[inline] fn sum(self, other: Self) -> Self { Grapheme(self.0 + other.0) }
}

impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}

impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(usize);
impl Monoid for Line {
    #[inline] fn identity() -> Self { Line(0) }
    #[inline] fn sum(self, other: Self) -> Self { Line(self.0 + other.0) }
}

impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}
<commit_msg>feat(rope): monoid uses `default()` for identity<commit_after>use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use internals::Node;

pub trait Semigroup {
    /// The sum operation of the semigroup
    fn sum(self, other: Self) -> Self;
}

/// The class of monoids
///
/// The class of monoids (types with an accumulative binary operation that has
/// an default).
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.sum(`_M_`::default())` = _x_
///  + _M_`::default().sum(`_x_`)` = _x_
///  + _x_`.sum(`_y_`.sum(`_z_`))` = _z_`.sum(`_x_`.sum(`_y_`))`
///  + _M_`::accumulate(`_a_`)` = _a_`.fold(`_M_`::default,`_M_`::sum)`
///
pub trait Monoid: Semigroup + Default + Sized {

    #[inline]
    fn accumulate<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::default(), Self::sum)
    }
}

/// A monoid that can be applied to a `Node` as a measurement
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                              + Sub<usize, Output=Self>
                              + Sized {
    /// Apply this `Metric` to the given `Node`
    fn measure(node: &Node) -> Self;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index(&self, node: &Node) -> Option<usize>;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline] fn next(self, node: &Node) -> Option<usize> {
        (self + 1).to_byte_index(node)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline] fn back(self, node: &Node) -> Option<usize> {
        (self - 1).to_byte_index(node)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    // TODO: should this be a method on `Node`s instead?
    fn is_boundary(node: &Node, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl Semigroup for Grapheme {
    #[inline] fn sum(self, other: Self) -> Self { Grapheme(self.0 + other.0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Semigroup for Line {
    #[inline] fn sum(self, other: Self) -> Self { Line(self.0 + other.0) }
}

impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}
<|endoftext|>


<commit_before>extern crate parking_lot;
extern crate owning_ref;

use parking_lot::{RwLock, RwLockWriteGuard, RwLockReadGuard};
use owning_ref::{OwningHandle, OwningRef};
use std::sync::atomic::{self, AtomicUsize};
use std::hash::{self, Hash, Hasher};
use std::{mem, ops};

const ORDERING: atomic::Ordering = atomic::Ordering::SeqCst;
const LENGTH_MULTIPLIER: usize = 4;
const MAX_LOAD_FACTOR_NUM: usize = 100 - 15;
const MAX_LOAD_FACTOR_DENOM: usize = 100;
const DEFAULT_INITIAL_SIZE: usize = 32;

fn hash<K: Hash>(key: K) -> usize {
    let mut h = hash::SipHasher::new();
    key.hash(&mut h);
    h.finish() as usize
}

enum Bucket<K, V> {
    Contains(K, V),
    Removed,
    Empty,
}

impl<K, V> Bucket<K, V> {
    fn remove(&mut self) -> Bucket<K, V> {
        mem::replace(self, Bucket::Removed)
    }

    fn value(self) -> Option<V> {
        if let Bucket::Contains(_, val) = self {
            Some(val)
        } else { None }
    }
}

struct Table<K, V> {
    buckets: Vec<RwLock<Bucket<K, V>>>,
}

impl<K: PartialEq + Hash, V> Table<K, V> {
    fn with_capacity(cap: usize) -> Table<K, V> {
        // TODO: For some obscure reason `RwLock` doesn't implement `Clone`.
        let mut vec = Vec::with_capacity(cap);
        for _ in 0..cap {
            vec.push(RwLock::new(Bucket::Empty));
        }

        Table {
            buckets: vec,
        }
    }

    fn scan<F>(&self, key: &K, matches: F) -> RwLockReadGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].read();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut<F>(&self, key: &K, matches: F) -> RwLockWriteGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].write();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut_no_lock<F>(&mut self, key: &K, matches: F) -> &mut Bucket<K, V>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let bucket = self.buckets[(hash + i) % len].get_mut();

            if matches(&bucket) {
                return bucket;
            }
        }

        unreachable!();
    }

    fn lookup(&self, key: &K) -> RwLockReadGuard<Bucket<K, V>> {
        self.scan(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn lookup_mut(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn find_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            // Halt if and only if the bucket is free.
            Bucket::Removed | Bucket::Empty => true,
            _ => false,
        })
    }

    fn fill(&mut self, table: Table<K, V>) {
        for mut i in table.buckets {
            if let Bucket::Contains(key, val) = i.get_mut().remove() {
                let mut bucket = self.scan_mut_no_lock(&key, |x| match *x {
                    Bucket::Removed | Bucket::Empty => true,
                    _ => false,
                });

                *bucket = Bucket::Contains(key, val);
            }
        }
    }
}

pub struct ReadGuard<'a, K: 'a, V: 'a> {
    inner: OwningRef<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockReadGuard<'a, Bucket<K, V>>>, V>,
}

impl<'a, K, V> ops::Deref for ReadGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

pub struct WriteGuard<'a, K: 'a, V: 'a> {
    inner: OwningHandle<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockWriteGuard<'a, Bucket<K, V>>>, &'a mut V>,
}

impl<'a, K, V> ops::Deref for WriteGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

impl<'a, K, V> ops::DerefMut for WriteGuard<'a, K, V> {
    fn deref_mut(&mut self) -> &mut V {
        &mut self.inner
    }
}

pub struct CHashMap<K, V> {
    total: AtomicUsize,
    table: RwLock<Table<K, V>>,
}

impl<K, V> CHashMap<K, V> {
    pub fn with_capacity(cap: usize) -> CHashMap<K, V> {
        CHashMap {
            total: AtomicUsize::new(0),
            table: RwLock::new(Table::with_capacity(cap)),
        }
    }

    pub fn new() -> CHashMap<K, V> {
        CHashMap::with_capacity(DEFAULT_INITIAL_SIZE)
    }
}

impl<K: PartialEq + Hash, V> CHashMap<K, V> {
    pub fn get(&self, key: &K) -> Option<ReadGuard<K, V>> {
        if let Ok(inner) = OwningRef::new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup(key)))
            .try_map(|x| if let Bucket::Contains(_, ref val) = *x {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(ReadGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn get_mut(&self, key: &K) -> Option<WriteGuard<K, V>> {
        if let Ok(inner) = OwningHandle::try_new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup_mut(key)), |x| if let &mut Bucket::Contains(_, ref mut val) = unsafe { &mut *(x as *mut Bucket<K, V>) } {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(WriteGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn insert(&self, key: K, val: V) {
        let lock = self.expand();
        let mut bucket = lock.find_free(&key);

        *bucket = Bucket::Contains(key, val);
    }

    pub fn replace(&self, key: K, val: V) -> Option<V> {
        let lock = self.expand();
        let mut bucket = lock.lookup_mut(&key);

        mem::replace(&mut *bucket, Bucket::Contains(key, val)).value()
    }

    pub fn remove(&self, key: &K) -> Option<V> {
        let lock = self.table.read();

        let mut bucket = lock.lookup_mut(&key);
        let ret = bucket.remove().value();

        if ret.is_some() {
            self.total.fetch_sub(1, ORDERING);
        }

        ret
    }

    pub fn reserve(&self, additional: usize) {
        let len = self.total.load(ORDERING) + additional;
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(len * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    pub fn shrink_to_fit(&self) {
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(self.total.load(ORDERING) * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    fn expand(&self) -> RwLockReadGuard<Table<K, V>> {
        let lock = self.table.read();
        let total = self.total.fetch_add(1, ORDERING) + 1;

        // Extend if necessary. We multiply by some constant to adjust our load factor.
        if total * MAX_LOAD_FACTOR_DENOM >= lock.buckets.len() * MAX_LOAD_FACTOR_NUM {
            drop(lock);

            {
                let mut lock = self.table.write();
                let table = mem::replace(&mut *lock, Table::with_capacity(total * LENGTH_MULTIPLIER));
                lock.fill(table);
            }

            self.table.read()
        } else {
            lock
        }
    }
}

impl<K, V> Default for CHashMap<K, V> {
    fn default() -> CHashMap<K, V> {
        CHashMap::new()
    }
}
<commit_msg>Add iterators over `CHashMap`.<commit_after>extern crate parking_lot;
extern crate owning_ref;

use parking_lot::{RwLock, RwLockWriteGuard, RwLockReadGuard};
use owning_ref::{OwningHandle, OwningRef};
use std::sync::atomic::{self, AtomicUsize};
use std::hash::{self, Hash, Hasher};
use std::{mem, ops};

const ORDERING: atomic::Ordering = atomic::Ordering::SeqCst;
const LENGTH_MULTIPLIER: usize = 4;
const MAX_LOAD_FACTOR_NUM: usize = 100 - 15;
const MAX_LOAD_FACTOR_DENOM: usize = 100;
const DEFAULT_INITIAL_SIZE: usize = 32;

fn hash<K: Hash>(key: K) -> usize {
    let mut h = hash::SipHasher::new();
    key.hash(&mut h);
    h.finish() as usize
}

enum Bucket<K, V> {
    Contains(K, V),
    Removed,
    Empty,
}

impl<K, V> Bucket<K, V> {
    fn is_free(&self) -> bool {
        match *self {
            Bucket::Removed | Bucket::Empty => true,
            _ => false,
        }
    }

    fn remove(&mut self) -> Bucket<K, V> {
        mem::replace(self, Bucket::Removed)
    }

    fn pair(self) -> Option<(K, V)> {
        if let Bucket::Contains(key, val) = self {
            Some((key, val))
        } else { None }
    }

    fn value(self) -> Option<V> {
        if let Bucket::Contains(_, val) = self {
            Some(val)
        } else { None }
    }

    fn value_ref(&self) -> Result<&V, ()> {
        if let Bucket::Contains(_, ref val) = *self {
            Ok(val)
        } else {
            Err(())
        }
    }
}

struct Table<K, V> {
    buckets: Vec<RwLock<Bucket<K, V>>>,
}

impl<K, V> Table<K, V> {
    fn with_capacity(cap: usize) -> Table<K, V> {
        // TODO: For some obscure reason `RwLock` doesn't implement `Clone`.
        let mut vec = Vec::with_capacity(cap);
        for _ in 0..cap {
            vec.push(RwLock::new(Bucket::Empty));
        }

        Table {
            buckets: vec,
        }
    }
}

impl<K: PartialEq + Hash, V> Table<K, V> {
    fn scan<F>(&self, key: &K, matches: F) -> RwLockReadGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].read();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut<F>(&self, key: &K, matches: F) -> RwLockWriteGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].write();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut_no_lock<F>(&mut self, key: &K, matches: F) -> &mut Bucket<K, V>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let bucket = self.buckets[(hash + i) % len].get_mut();

            if matches(&bucket) {
                return bucket;
            }
        }

        unreachable!();
    }

    fn lookup(&self, key: &K) -> RwLockReadGuard<Bucket<K, V>> {
        self.scan(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn lookup_mut(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn find_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| x.is_free())
    }

    fn fill(&mut self, table: Table<K, V>) {
        for mut i in table.buckets {
            if let Bucket::Contains(key, val) = i.get_mut().remove() {
                let mut bucket = self.scan_mut_no_lock(&key, |x| match *x {
                    Bucket::Removed | Bucket::Empty => true,
                    _ => false,
                });

                *bucket = Bucket::Contains(key, val);
            }
        }
    }
}

pub struct IntoIter<K, V> {
    table: Table<K, V>,
}

impl<K, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);

    fn next(&mut self) -> Option<(K, V)> {
        while let Some(bucket) = self.table.buckets.pop() {
            let ret = bucket.into_inner().pair();
            if ret.is_some() {
                return ret;
            }
        }

        None
    }
}

impl<K, V> IntoIterator for Table<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;

    fn into_iter(mut self) -> IntoIter<K, V> {
        IntoIter {
            table: self,
        }
    }
}

pub struct ReadGuard<'a, K: 'a, V: 'a> {
    inner: OwningRef<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockReadGuard<'a, Bucket<K, V>>>, V>,
}

impl<'a, K, V> ops::Deref for ReadGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

pub struct WriteGuard<'a, K: 'a, V: 'a> {
    inner: OwningHandle<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockWriteGuard<'a, Bucket<K, V>>>, &'a mut V>,
}

impl<'a, K, V> ops::Deref for WriteGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

impl<'a, K, V> ops::DerefMut for WriteGuard<'a, K, V> {
    fn deref_mut(&mut self) -> &mut V {
        &mut self.inner
    }
}

pub struct CHashMap<K, V> {
    total: AtomicUsize,
    table: RwLock<Table<K, V>>,
}

impl<K, V> CHashMap<K, V> {
    pub fn with_capacity(cap: usize) -> CHashMap<K, V> {
        CHashMap {
            total: AtomicUsize::new(0),
            table: RwLock::new(Table::with_capacity(cap)),
        }
    }

    pub fn new() -> CHashMap<K, V> {
        CHashMap::with_capacity(DEFAULT_INITIAL_SIZE)
    }
}

impl<K: PartialEq + Hash, V> CHashMap<K, V> {
    pub fn get(&self, key: &K) -> Option<ReadGuard<K, V>> {
        if let Ok(inner) = OwningRef::new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup(key)))
            .try_map(|x| x.value_ref()) {
            Some(ReadGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn get_mut(&self, key: &K) -> Option<WriteGuard<K, V>> {
        if let Ok(inner) = OwningHandle::try_new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup_mut(key)), |x| if let &mut Bucket::Contains(_, ref mut val) = unsafe { &mut *(x as *mut Bucket<K, V>) } {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(WriteGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn insert(&self, key: K, val: V) {
        let lock = self.expand();
        let mut bucket = lock.find_free(&key);

        *bucket = Bucket::Contains(key, val);
    }

    pub fn replace(&self, key: K, val: V) -> Option<V> {
        let lock = self.expand();
        let mut bucket = lock.lookup_mut(&key);

        mem::replace(&mut *bucket, Bucket::Contains(key, val)).value()
    }

    pub fn remove(&self, key: &K) -> Option<V> {
        let lock = self.table.read();

        let mut bucket = lock.lookup_mut(&key);
        let ret = bucket.remove().value();

        if ret.is_some() {
            self.total.fetch_sub(1, ORDERING);
        }

        ret
    }

    pub fn reserve(&self, additional: usize) {
        let len = self.total.load(ORDERING) + additional;
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(len * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    pub fn shrink_to_fit(&self) {
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(self.total.load(ORDERING) * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    fn expand(&self) -> RwLockReadGuard<Table<K, V>> {
        let lock = self.table.read();
        let total = self.total.fetch_add(1, ORDERING) + 1;

        // Extend if necessary. We multiply by some constant to adjust our load factor.
        if total * MAX_LOAD_FACTOR_DENOM >= lock.buckets.len() * MAX_LOAD_FACTOR_NUM {
            drop(lock);

            {
                let mut lock = self.table.write();
                let table = mem::replace(&mut *lock, Table::with_capacity(total * LENGTH_MULTIPLIER));
                lock.fill(table);
            }

            self.table.read()
        } else {
            lock
        }
    }
}

impl<K, V> Default for CHashMap<K, V> {
    fn default() -> CHashMap<K, V> {
        CHashMap::new()
    }
}

impl<K, V> IntoIterator for CHashMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;

    fn into_iter(mut self) -> IntoIter<K, V> {
        self.table.into_inner().into_iter()
    }
}
<|endoftext|>


<commit_before>use crate::{LexedStr, PrefixEntryPoint, Step};

#[test]
fn vis() {
    check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
    check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
    check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
    check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
    check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
}

#[test]
fn block() {
    check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
    check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
    check_prefix(PrefixEntryPoint::Block, "()", "");
}

#[test]
fn stmt() {
    check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
    check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
    check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
    check_prefix(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
    check_prefix(PrefixEntryPoint::Stmt, "+", "+");
    check_prefix(PrefixEntryPoint::Stmt, "@", "@");
    check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
}

#[test]
fn pat() {
    check_prefix(PrefixEntryPoint::Pat, "x y", "x");
    check_prefix(PrefixEntryPoint::Pat, "fn f() {}", "fn");
    // FIXME: This one is wrong, we should consume only one pattern.
    check_prefix(PrefixEntryPoint::Pat, ".. ..", ".. ..");
}

#[test]
fn ty() {
    check_prefix(PrefixEntryPoint::Ty, "fn() foo", "fn()");
    check_prefix(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
    check_prefix(PrefixEntryPoint::Ty, "struct f", "struct");
}

#[test]
fn expr() {
    check_prefix(PrefixEntryPoint::Expr, "92 92", "92");
    check_prefix(PrefixEntryPoint::Expr, "+1", "+");
    check_prefix(PrefixEntryPoint::Expr, "-1", "-1");
    check_prefix(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
    check_prefix(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
}

fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
    let lexed = LexedStr::new(input);
    let input = lexed.to_input();

    let mut n_tokens = 0;
    for step in entry.parse(&input).iter() {
        match step {
            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
        }
    }

    let mut i = 0;
    loop {
        if n_tokens == 0 {
            break;
        }
        if !lexed.kind(i).is_trivia() {
            n_tokens -= 1;
        }
        i += 1;
    }
    let buf = &lexed.as_str()[..lexed.text_start(i)];
    assert_eq!(buf, prefix);
}
<commit_msg>add path tests<commit_after>use crate::{LexedStr, PrefixEntryPoint, Step};

#[test]
fn vis() {
    check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
    check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
    check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
    check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
    check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
}

#[test]
fn block() {
    check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
    check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
    check_prefix(PrefixEntryPoint::Block, "()", "");
}

#[test]
fn stmt() {
    check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
    check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
    check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
    check_prefix(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
    check_prefix(PrefixEntryPoint::Stmt, "+", "+");
    check_prefix(PrefixEntryPoint::Stmt, "@", "@");
    check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
}

#[test]
fn pat() {
    check_prefix(PrefixEntryPoint::Pat, "x y", "x");
    check_prefix(PrefixEntryPoint::Pat, "fn f() {}", "fn");
    // FIXME: This one is wrong, we should consume only one pattern.
    check_prefix(PrefixEntryPoint::Pat, ".. ..", ".. ..");
}

#[test]
fn ty() {
    check_prefix(PrefixEntryPoint::Ty, "fn() foo", "fn()");
    check_prefix(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
    check_prefix(PrefixEntryPoint::Ty, "struct f", "struct");
}

#[test]
fn expr() {
    check_prefix(PrefixEntryPoint::Expr, "92 92", "92");
    check_prefix(PrefixEntryPoint::Expr, "+1", "+");
    check_prefix(PrefixEntryPoint::Expr, "-1", "-1");
    check_prefix(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
    check_prefix(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
}

#[test]
fn path() {
    check_prefix(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
    check_prefix(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
    check_prefix(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
    check_prefix(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
    // FIXME: this shouldn't be accepted as path actually.
    check_prefix(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
}

fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
    let lexed = LexedStr::new(input);
    let input = lexed.to_input();

    let mut n_tokens = 0;
    for step in entry.parse(&input).iter() {
        match step {
            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
        }
    }

    let mut i = 0;
    loop {
        if n_tokens == 0 {
            break;
        }
        if !lexed.kind(i).is_trivia() {
            n_tokens -= 1;
        }
        i += 1;
    }
    let buf = &lexed.as_str()[..lexed.text_start(i)];
    assert_eq!(buf, prefix);
}
<|endoftext|>


<commit_before>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        self.files.watcher = match get(value, "/files/watcher") {
            Some("client") => FilesWatcher::Client,
            Some("notify") | _ => FilesWatcher::Notify
        };
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        if let Some(mut args) = get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            if !args.is_empty() {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
        } else if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
            set(value, "/rustfmt/extraArgs", extra_args);
        }

        if let Some(false) = get(value, "/checkOnSave/enable") {
            self.check = None;
        } else {
            if let Some(mut args) = get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                if !args.is_empty() {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    });
                }

            } else if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
            {
                set(value, "/checkOnSave/extraArgs", extra_args);
                set(value, "/checkOnSave/command", command);
                set(value, "/checkOnSave/allTargets", all_targets);
            }
        };

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<commit_msg>fix cargo check config with custom command<commit_after>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        self.files.watcher = match get(value, "/files/watcher") {
            Some("client") => FilesWatcher::Client,
            Some("notify") | _ => FilesWatcher::Notify
        };
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        match get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            Some(mut args) if !args.is_empty() => {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
            _ => {
                if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
                    set(value, "/rustfmt/extraArgs", extra_args);
                }
            }
        };

        if let Some(false) = get(value, "/checkOnSave/enable") {
            // check is disabled
            self.check = None;
        } else {
            // check is enabled
            match get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                // first see if the user has completely overridden the command
                Some(mut args) if !args.is_empty() => {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    });
                }
                // otherwise configure command customizations
                _ => {
                    if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets })
                        = &mut self.check
                    {
                        set(value, "/checkOnSave/extraArgs", extra_args);
                        set(value, "/checkOnSave/command", command);
                        set(value, "/checkOnSave/allTargets", all_targets);
                    }
                }
            };
        }

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Some functions to escape character for display in HTML or LaTeX.
//!
//! The two most useful ones are `tex` and `html`.
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::escape;
//! let input = "<foo> & <bar>";
//! let output = escape::html(input);
//! assert_eq!(&output, "<foo> & <bar>");
//!
//! let input = "#2: 20%";
//! let output = escape::tex(input);
//! assert_eq!(&output, r"\#2: 20\%");
//! ```

use std::borrow::Cow;

use regex::Regex;

use common::{NB_CHAR, NB_CHAR_NARROW, NB_CHAR_EM};

/// Escape non breaking spaces for HTML.
///
/// This is done so there is no problem for
/// displaying them if the font or browser doesn't know what to do
/// with them (particularly the narrow non breaking space which isn't
/// very well supported).
///
/// In order to work correctly, this will require a CSS style with
///
/// ```css
/// .nnbsp {
///    white-space: nowrap;
/// }
/// ```
///
/// Else, narrow spaces won't be no-breaking, and that might be ugly.
pub fn nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW => output.push_str(r#" "#),
                NB_CHAR_EM => output.push_str(r#" "#),
                NB_CHAR => output.push_str(r#" "#),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape non breaking spaces for LaTeX, replacing them with `~`.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::nb_spaces_tex("Des espaces insécables ? Ça alors !");
/// assert_eq!(&s, "Des espaces insécables~? Ça alors~!");
/// ```
pub fn nb_spaces_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW | NB_CHAR_EM | NB_CHAR => output.push('~'),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for HTML output, replacing  `<`, `>`, and `&` with appropriate
/// HTML entities.
///
/// **Warning**: this function was written for escaping text in a markdown
/// text processor that is designed to run on a local machine, where the content
/// can actually be trusted. It should *not* be used for untrusted content.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[<>&]").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let rest = input[first..].bytes();
        for c in rest {
            match c {
                b'<' => output.extend_from_slice(b"<"),
                b'>' => output.extend_from_slice(b">"),
                b'&' => output.extend_from_slice(b"&"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

/// Escape quotes
///
/// Simply replace `"` by `'`
pub fn quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains('"') {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                '"' => output.push('\''),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}

/// Escape characters for LaTeX
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    const REGEX_LITERAL: &'static str = r"[&%$#_\x7E\x2D\{\}\^\\]";
    lazy_static! {
       static ref REGEX: Regex = Regex::new(REGEX_LITERAL).unwrap();
    }

    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let mut bytes: Vec<_> = input[first..].bytes().collect();
        bytes.push(b' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in bytes.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                b'-' => {
                    if next == b'-' {
                        // if next char is also a -, to avoid tex ligatures
                        output.extend_from_slice(br"-{}");
                    } else {
                        output.push(c);
                    }
                }
                b'&' => output.extend_from_slice(br"\&"),
                b'%' => output.extend_from_slice(br"\%"),
                b'$' => output.extend_from_slice(br"\$"),
                b'#' => output.extend_from_slice(br"\#"),
                b'_' => output.extend_from_slice(br"\_"),
                b'{' => output.extend_from_slice(br"\{"),
                b'}' => output.extend_from_slice(br"\}"),
                b'~' => output.extend_from_slice(br"\textasciitilde{}"),
                b'^' => output.extend_from_slice(br"\textasciicircum{}"),
                b'\\' => output.extend_from_slice(br"\textbackslash{}"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

#[test]
fn html_0() {
    let s = "Some string without any character to escape";
    let result = html(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_0() {
    let s = "Some string without any character to escape";
    let result = tex(s);
    assert_eq!(s, &result);
}

#[test]
fn nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces_tex(s);
    assert_eq!(s, &result);
}

#[test]
fn quotes_0() {
    let s = "Some string without any character to escape";
    let result = quotes(s);
    assert_eq!(s, &result);
}

#[test]
fn html_1() {
    let s = "
Some characters need escaping & something
";
    let expected = "<p>Some characters need escaping & something</p>";
    let actual = html(s);
    assert_eq!(expected, &actual);
}

#[test]
fn html_2() {
    let actual = html("<foo> & <bar>");
    let expected = "<foo> & <bar>";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_braces() {
    let actual = tex(r"\foo{bar}");
    let expected = r"\textbackslash{}foo\{bar\}";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_dashes() {
    let actual = tex("--foo, ---bar");
    let expected = r"-{}-foo, -{}-{}-bar";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_numbers() {
    let actual = tex(r"30000$ is 10% of number #1 income");
    let expected = r"30000\$ is 10\% of number \#1 income";
    assert_eq!(&actual, expected);
}

#[test]
fn quotes_escape() {
    let actual = quotes(r#"Some text with "quotes""#);
    let expected = r#"Some text with 'quotes'"#;
    assert_eq!(&actual, expected);
}

#[test]
fn nb_spaces_escape() {
    let actual = nb_spaces("This contains non breaking spaces");
    let expected = "This contains\
                     non breaking spaces";
    assert_eq!(&actual, expected);
}
<commit_msg>Update escape::quotes doc<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Some functions to escape character for display in HTML or LaTeX.
//!
//! The two most useful ones are `tex` and `html`.
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::escape;
//! let input = "<foo> & <bar>";
//! let output = escape::html(input);
//! assert_eq!(&output, "<foo> & <bar>");
//!
//! let input = "#2: 20%";
//! let output = escape::tex(input);
//! assert_eq!(&output, r"\#2: 20\%");
//! ```

use std::borrow::Cow;

use regex::Regex;

use common::{NB_CHAR, NB_CHAR_NARROW, NB_CHAR_EM};

/// Escape non breaking spaces for HTML.
///
/// This is done so there is no problem for
/// displaying them if the font or browser doesn't know what to do
/// with them (particularly the narrow non breaking space which isn't
/// very well supported).
///
/// In order to work correctly, this will require a CSS style with
///
/// ```css
/// .nnbsp {
///    white-space: nowrap;
/// }
/// ```
///
/// Else, narrow spaces won't be no-breaking, and that might be ugly.
pub fn nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW => output.push_str(r#" "#),
                NB_CHAR_EM => output.push_str(r#" "#),
                NB_CHAR => output.push_str(r#" "#),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape non breaking spaces for LaTeX, replacing them with `~`.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::nb_spaces_tex("Des espaces insécables ? Ça alors !");
/// assert_eq!(&s, "Des espaces insécables~? Ça alors~!");
/// ```
pub fn nb_spaces_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW | NB_CHAR_EM | NB_CHAR => output.push('~'),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for HTML output, replacing  `<`, `>`, and `&` with appropriate
/// HTML entities.
///
/// **Warning**: this function was written for escaping text in a markdown
/// text processor that is designed to run on a local machine, where the content
/// can actually be trusted. It should *not* be used for untrusted content.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[<>&]").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let rest = input[first..].bytes();
        for c in rest {
            match c {
                b'<' => output.extend_from_slice(b"<"),
                b'>' => output.extend_from_slice(b">"),
                b'&' => output.extend_from_slice(b"&"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

/// Very naively escape quotes
///
/// Simply replace `"` by `'`
pub fn quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains('"') {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                '"' => output.push('\''),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}

/// Escape characters for LaTeX
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    const REGEX_LITERAL: &'static str = r"[&%$#_\x7E\x2D\{\}\^\\]";
    lazy_static! {
       static ref REGEX: Regex = Regex::new(REGEX_LITERAL).unwrap();
    }

    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let mut bytes: Vec<_> = input[first..].bytes().collect();
        bytes.push(b' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in bytes.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                b'-' => {
                    if next == b'-' {
                        // if next char is also a -, to avoid tex ligatures
                        output.extend_from_slice(br"-{}");
                    } else {
                        output.push(c);
                    }
                }
                b'&' => output.extend_from_slice(br"\&"),
                b'%' => output.extend_from_slice(br"\%"),
                b'$' => output.extend_from_slice(br"\$"),
                b'#' => output.extend_from_slice(br"\#"),
                b'_' => output.extend_from_slice(br"\_"),
                b'{' => output.extend_from_slice(br"\{"),
                b'}' => output.extend_from_slice(br"\}"),
                b'~' => output.extend_from_slice(br"\textasciitilde{}"),
                b'^' => output.extend_from_slice(br"\textasciicircum{}"),
                b'\\' => output.extend_from_slice(br"\textbackslash{}"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

#[test]
fn html_0() {
    let s = "Some string without any character to escape";
    let result = html(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_0() {
    let s = "Some string without any character to escape";
    let result = tex(s);
    assert_eq!(s, &result);
}

#[test]
fn nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces_tex(s);
    assert_eq!(s, &result);
}

#[test]
fn quotes_0() {
    let s = "Some string without any character to escape";
    let result = quotes(s);
    assert_eq!(s, &result);
}

#[test]
fn html_1() {
    let s = "
Some characters need escaping & something
";
    let expected = "<p>Some characters need escaping & something</p>";
    let actual = html(s);
    assert_eq!(expected, &actual);
}

#[test]
fn html_2() {
    let actual = html("<foo> & <bar>");
    let expected = "<foo> & <bar>";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_braces() {
    let actual = tex(r"\foo{bar}");
    let expected = r"\textbackslash{}foo\{bar\}";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_dashes() {
    let actual = tex("--foo, ---bar");
    let expected = r"-{}-foo, -{}-{}-bar";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_numbers() {
    let actual = tex(r"30000$ is 10% of number #1 income");
    let expected = r"30000\$ is 10\% of number \#1 income";
    assert_eq!(&actual, expected);
}

#[test]
fn quotes_escape() {
    let actual = quotes(r#"Some text with "quotes""#);
    let expected = r#"Some text with 'quotes'"#;
    assert_eq!(&actual, expected);
}

#[test]
fn nb_spaces_escape() {
    let actual = nb_spaces("This contains non breaking spaces");
    let expected = "This contains\
                     non breaking spaces";
    assert_eq!(&actual, expected);
}
<|endoftext|>