<commit_before>use nannou::prelude::*;

pub struct QuadTree<T> {
    indices: [usize; 4],
    num: usize,
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    whatever: Option<T>,
    pub children: Option<[Box<QuadTree<T>> ; 4]>,
}

pub trait WithPos {
    fn get_pos(&self) -> Vector2;
}

impl <T: WithPos> QuadTree<T> {
    pub fn new() -> Self {
        QuadTree{
            indices: [0; 4],
            num: 0,
            x: 0.0,
            y: 0.0,
            width: 1024.0,
            height: 1024.0,
            whatever: None,
            children: None,
        }
    }

    pub fn contains(&self, point: &T) -> bool {
        let pos = point.get_pos();
        pos.x >= self.x - self.width*0.5 && pos.x < self.x +self.width*0.5
            && pos.y >= self.y - self.height*0.5 && pos.y < self.y + self.height*0.5

    }

    //split in four
    //mutates self
    pub fn split(&mut self, elements: &Vec<T>) {
        //let new_children =
        let mut southwest: Box<QuadTree<T>> = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x-self.width*0.25,
            y: self.y-self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut southeast : Box<QuadTree<T>> = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x+self.width*0.25,
            y: self.y-self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut northwest: Box<QuadTree<T>>  = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x-self.width*0.25,
            y: self.y+self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut northeast: Box<QuadTree<T>>  = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x+self.width*0.25,
            y: self.y+self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        //push the elements down the children
        for k in 0..self.num {
            let point = &elements[self.indices[k]];
            if northwest.contains(&point) {
                northwest.insert(elements, self.indices[k]);
            } else if northeast.contains(point) {
                northeast.insert(elements, self.indices[k]);
            } else if southeast.contains(point) {
                southeast.insert(elements, self.indices[k]);
            } else if southwest.contains(point) {
                southwest.insert(elements, self.indices[k]);
            }
        }
        self.children = Some([northwest, northeast, southwest, southeast]);

    }

    pub fn insert_children(&mut self, elements: &Vec<T>, index: usize){
        match self.children.as_mut() {
            Some(children) => {
                //TODO faster sort
                    if children[0].contains(&elements[index]) {
                        children[0].insert(elements, index);
                    } else if children[1].contains(&elements[index]) {
                        children[1].insert(elements, index);
                    } else if children[2].contains(&elements[index]) {
                        children[2].insert(elements, index);
                    } else if children[3].contains(&elements[index]) {
                        children[3].insert(elements, index);
                    }

            },
            None => {
            },
        }
    }

    pub fn intersects(&self, x:f32, y: f32, dist:f32) -> bool {
        //think of the inverse, if one rect is completely on the side of another
        if x+dist < self.x-self.width*0.5 || x-dist > self.x+self.width*0.5 {
            return false;
        }
        if y+dist < self.y-self.height*0.5 || y-dist > self.y+self.height*0.5 {
            return false;
        }

        return true;

    }

    pub fn get_elements(&self, elements: &Vec<T>, x: f32, y: f32, dist: f32) -> Vec<usize> {
        let mut result: Vec<usize> = Vec::new();

        //are we intersecting the rect
        if self.intersects(x,y,dist) {
            //if we have children, recurse
            match &self.children {
                Some(children) => {
                    let mut r0 = children[0].get_elements(elements,x,y,dist);
                    let mut r1 = children[1].get_elements(elements,x,y,dist);
                    let mut r2 = children[2].get_elements(elements,x,y,dist);
                    let mut r3 = children[3].get_elements(elements,x,y,dist);
                    result.append(&mut r0);
                    result.append(&mut r1);
                    result.append(&mut r2);
                    result.append(&mut r3);
                },
                None => {
                    //no children, return all elements?
                    for i in 0..self.num {
                        result.push(self.indices[i]);
                    }

                },
            }
        }
        result
    }

    pub fn insert(&mut self, elements: &Vec<T>, index: usize){
        //have we split?
        match &self.children {
            Some(children) => {
                    self.insert_children(elements, index);
            },
            None => {
                if self.num < 4 {
                    self.indices[self.num]=index;
                    self.num +=1;
                } else {
                    //we are full
                    // we must split and push down the elements
                    self.split(elements);
                    //add this to children
                    self.insert_children(elements, index);
                }
            },
        }

    }

}
<commit_msg>added names<commit_after>// Simple QuadTree
// Alexis Andre (@mactuitui)

use nannou::prelude::*;

pub struct QuadTree<T> {
    indices: [usize; 4],
    num: usize,
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    whatever: Option<T>,
    pub children: Option<[Box<QuadTree<T>> ; 4]>,
}

pub trait WithPos {
    fn get_pos(&self) -> Vector2;
}

impl <T: WithPos> QuadTree<T> {
    pub fn new() -> Self {
        QuadTree{
            indices: [0; 4],
            num: 0,
            x: 0.0,
            y: 0.0,
            width: 1024.0,
            height: 1024.0,
            whatever: None,
            children: None,
        }
    }

    pub fn contains(&self, point: &T) -> bool {
        let pos = point.get_pos();
        pos.x >= self.x - self.width*0.5 && pos.x < self.x +self.width*0.5
            && pos.y >= self.y - self.height*0.5 && pos.y < self.y + self.height*0.5

    }

    //split in four
    //mutates self
    pub fn split(&mut self, elements: &Vec<T>) {
        //let new_children =
        let mut southwest: Box<QuadTree<T>> = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x-self.width*0.25,
            y: self.y-self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut southeast : Box<QuadTree<T>> = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x+self.width*0.25,
            y: self.y-self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut northwest: Box<QuadTree<T>>  = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x-self.width*0.25,
            y: self.y+self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        let mut northeast: Box<QuadTree<T>>  = Box::new(QuadTree::<T>{
            indices: [0; 4],
            num: 0,
            x: self.x+self.width*0.25,
            y: self.y+self.height*0.25,
            width: self.width*0.5,
            height: self.height*0.5,
            whatever: None,
            children: None,
        });
        //push the elements down the children
        for k in 0..self.num {
            let point = &elements[self.indices[k]];
            if northwest.contains(&point) {
                northwest.insert(elements, self.indices[k]);
            } else if northeast.contains(point) {
                northeast.insert(elements, self.indices[k]);
            } else if southeast.contains(point) {
                southeast.insert(elements, self.indices[k]);
            } else if southwest.contains(point) {
                southwest.insert(elements, self.indices[k]);
            }
        }
        self.children = Some([northwest, northeast, southwest, southeast]);

    }

    pub fn insert_children(&mut self, elements: &Vec<T>, index: usize){
        match self.children.as_mut() {
            Some(children) => {
                //TODO faster sort
                    if children[0].contains(&elements[index]) {
                        children[0].insert(elements, index);
                    } else if children[1].contains(&elements[index]) {
                        children[1].insert(elements, index);
                    } else if children[2].contains(&elements[index]) {
                        children[2].insert(elements, index);
                    } else if children[3].contains(&elements[index]) {
                        children[3].insert(elements, index);
                    }

            },
            None => {
            },
        }
    }

    pub fn intersects(&self, x:f32, y: f32, dist:f32) -> bool {
        //think of the inverse, if one rect is completely on the side of another
        if x+dist < self.x-self.width*0.5 || x-dist > self.x+self.width*0.5 {
            return false;
        }
        if y+dist < self.y-self.height*0.5 || y-dist > self.y+self.height*0.5 {
            return false;
        }

        return true;

    }

    pub fn get_elements(&self, elements: &Vec<T>, x: f32, y: f32, dist: f32) -> Vec<usize> {
        let mut result: Vec<usize> = Vec::new();

        //are we intersecting the rect
        if self.intersects(x,y,dist) {
            //if we have children, recurse
            match &self.children {
                Some(children) => {
                    let mut r0 = children[0].get_elements(elements,x,y,dist);
                    let mut r1 = children[1].get_elements(elements,x,y,dist);
                    let mut r2 = children[2].get_elements(elements,x,y,dist);
                    let mut r3 = children[3].get_elements(elements,x,y,dist);
                    result.append(&mut r0);
                    result.append(&mut r1);
                    result.append(&mut r2);
                    result.append(&mut r3);
                },
                None => {
                    //no children, return all elements?
                    for i in 0..self.num {
                        result.push(self.indices[i]);
                    }

                },
            }
        }
        result
    }

    pub fn insert(&mut self, elements: &Vec<T>, index: usize){
        //have we split?
        match &self.children {
            Some(children) => {
                    self.insert_children(elements, index);
            },
            None => {
                if self.num < 4 {
                    self.indices[self.num]=index;
                    self.num +=1;
                } else {
                    //we are full
                    // we must split and push down the elements
                    self.split(elements);
                    //add this to children
                    self.insert_children(elements, index);
                }
            },
        }

    }

}
<|endoftext|>


<commit_before>#![feature(fs_walk)]

extern crate eve;

use std::env;
use std::fs::{OpenOptions, walk_dir};
use std::io::prelude::*;

use eve::server::*;
use eve::value::*;

#[test]
fn test_examples() {
    let inputs = walk_dir("./test-inputs").unwrap().collect::<Vec<_>>();
    let outputs = walk_dir("./test-outputs").unwrap().collect::<Vec<_>>();
    assert_eq!(inputs.len(), outputs.len());
    for (input_entry, output_entry) in inputs.into_iter().zip(outputs.into_iter()) {
        let input_filename = input_entry.unwrap().path().to_str().unwrap().to_owned();
        let output_filename = output_entry.unwrap().path().to_str().unwrap().to_owned();
        println!("Testing {:?} against {:?}", input_filename, output_filename);
        let flow = load(&input_filename[..]);
        let mut output_string = String::new();
        let mut output_file = OpenOptions::new().open(output_filename).unwrap();
        output_file.read_to_string(&mut output_string).unwrap();
        let output = Json::from_str(&output_string).unwrap();
        for (view_id, json) in output.as_object().unwrap().iter() {
            let test_rows: Vec<Vec<Value>> = flow.get_output(&view_id[..]).index.clone().into_iter().collect();
            let output_rows: Vec<Vec<Value>> = FromJson::from_json(json);
            assert_eq!(test_rows, output_rows);
        }
    }
}

#[allow(dead_code)]
fn main() {
	for argument in env::args() {
    	match &*argument {
    		"clean" => {
    			OpenOptions::new().create(true).truncate(true).open("./events").unwrap();
    			()
    		},
    		_ => continue,
    	}
	}

    run()
}<commit_msg>Ooops, tests needed that unused import<commit_after>#![feature(fs_walk)]

extern crate rustc_serialize;
extern crate eve;

use std::env;
use std::fs::{OpenOptions, walk_dir};
use std::io::prelude::*;
use rustc_serialize::json::Json;

use eve::server::*;
use eve::value::*;

#[test]
fn test_examples() {
    let inputs = walk_dir("./test-inputs").unwrap().collect::<Vec<_>>();
    let outputs = walk_dir("./test-outputs").unwrap().collect::<Vec<_>>();
    assert_eq!(inputs.len(), outputs.len());
    for (input_entry, output_entry) in inputs.into_iter().zip(outputs.into_iter()) {
        let input_filename = input_entry.unwrap().path().to_str().unwrap().to_owned();
        let output_filename = output_entry.unwrap().path().to_str().unwrap().to_owned();
        println!("Testing {:?} against {:?}", input_filename, output_filename);
        let flow = load(&input_filename[..]);
        let mut output_string = String::new();
        let mut output_file = OpenOptions::new().open(output_filename).unwrap();
        output_file.read_to_string(&mut output_string).unwrap();
        let output = Json::from_str(&output_string).unwrap();
        for (view_id, json) in output.as_object().unwrap().iter() {
            let test_rows: Vec<Vec<Value>> = flow.get_output(&view_id[..]).index.clone().into_iter().collect();
            let output_rows: Vec<Vec<Value>> = FromJson::from_json(json);
            assert_eq!(test_rows, output_rows);
        }
    }
}

#[allow(dead_code)]
fn main() {
	for argument in env::args() {
    	match &*argument {
    		"clean" => {
    			OpenOptions::new().create(true).truncate(true).open("./events").unwrap();
    			()
    		},
    		_ => continue,
    	}
	}

    run()
}<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::{
    fmt::{Display, Formatter},
    result,
};

use kvm_bindings::KVM_API_VERSION;
use kvm_ioctls::Kvm;

/// Errors associated with the wrappers over KVM ioctls.
#[derive(Debug)]
pub enum Error {
    /// The host kernel reports an invalid KVM API version.
    KvmApiVersion(i32),
    /// Cannot initialize the KVM context due to missing capabilities.
    KvmCap(kvm_ioctls::Cap),
}

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

        match self {
            KvmApiVersion(v) => write!(
                f,
                "The host kernel reports an invalid KVM API version: {}",
                v
            ),
            KvmCap(cap) => write!(f, "Missing KVM capabilities: {:?}", cap),
        }
    }
}

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

/// Describes a KVM context that gets attached to the microVM.
/// It gives access to the functionality of the KVM wrapper as
/// long as every required KVM capability is present on the host.
pub struct KvmContext {
    kvm: Kvm,
    max_memslots: usize,
}

impl KvmContext {
    pub fn new() -> Result<Self> {
        use kvm_ioctls::Cap::*;
        let kvm = Kvm::new().expect("Error creating the Kvm object");

        // Check that KVM has the correct version.
        if kvm.get_api_version() != KVM_API_VERSION as i32 {
            return Err(Error::KvmApiVersion(kvm.get_api_version()));
        }

        // A list of KVM capabilities we want to check.
        #[cfg(target_arch = "x86_64")]
        let capabilities = vec![Irqchip, Ioeventfd, Irqfd, UserMemory, SetTssAddr];

        #[cfg(target_arch = "aarch64")]
        let capabilities = vec![Irqchip, Ioeventfd, Irqfd, UserMemory, ArmPsci02];

        // Check that all desired capabilities are supported.
        match capabilities
            .iter()
            .find(|&capability| !kvm.check_extension(*capability))
        {
            None => {
                let max_memslots = kvm.get_nr_memslots();
                Ok(KvmContext { kvm, max_memslots })
            }

            Some(c) => Err(Error::KvmCap(*c)),
        }
    }

    pub fn fd(&self) -> &Kvm {
        &self.kvm
    }

    /// Get the maximum number of memory slots reported by this KVM context.
    pub fn max_memslots(&self) -> usize {
        self.max_memslots
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;

    use super::*;

    #[test]
    fn test_kvm_context() {
        use std::os::unix::fs::MetadataExt;
        use std::os::unix::io::{AsRawFd, FromRawFd};

        let c = KvmContext::new().unwrap();

        assert!(c.max_memslots() >= 32);

        let kvm = Kvm::new().unwrap();
        let f = unsafe { File::from_raw_fd(kvm.as_raw_fd()) };
        let m1 = f.metadata().unwrap();
        let m2 = File::open("/dev/kvm").unwrap().metadata().unwrap();

        assert_eq!(m1.dev(), m2.dev());
        assert_eq!(m1.ino(), m2.ino());
    }
}
<commit_msg>Update KVM compatibility checks<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::{
    fmt::{Display, Formatter},
    result,
};

use kvm_bindings::KVM_API_VERSION;
use kvm_ioctls::Kvm;

/// Errors associated with the wrappers over KVM ioctls.
#[derive(Debug)]
pub enum Error {
    /// The host kernel reports an invalid KVM API version.
    KvmApiVersion(i32),
    /// Cannot initialize the KVM context due to missing capabilities.
    KvmCap(kvm_ioctls::Cap),
}

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

        match self {
            KvmApiVersion(v) => write!(
                f,
                "The host kernel reports an invalid KVM API version: {}",
                v
            ),
            KvmCap(cap) => write!(f, "Missing KVM capabilities: {:?}", cap),
        }
    }
}

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

/// Describes a KVM context that gets attached to the microVM.
/// It gives access to the functionality of the KVM wrapper as
/// long as every required KVM capability is present on the host.
pub struct KvmContext {
    kvm: Kvm,
    max_memslots: usize,
}

impl KvmContext {
    pub fn new() -> Result<Self> {
        use kvm_ioctls::Cap::*;
        let kvm = Kvm::new().expect("Error creating the Kvm object");

        // Check that KVM has the correct version.
        if kvm.get_api_version() != KVM_API_VERSION as i32 {
            return Err(Error::KvmApiVersion(kvm.get_api_version()));
        }

        // A list of KVM capabilities we want to check.
        #[cfg(target_arch = "x86_64")]
        let capabilities = vec![
            Irqchip,
            Ioeventfd,
            Irqfd,
            UserMemory,
            SetTssAddr,
            Pit2,
            PitState2,
            AdjustClock,
            Debugregs,
            MpState,
            VcpuEvents,
            Xcrs,
            Xsave,
            ExtCpuid,
        ];

        #[cfg(target_arch = "aarch64")]
        let capabilities = vec![
            Irqchip, Ioeventfd, Irqfd, UserMemory, ArmPsci02, DeviceCtrl, MpState,
        ];

        // Check that all desired capabilities are supported.
        match capabilities
            .iter()
            .find(|&capability| !kvm.check_extension(*capability))
        {
            None => {
                let max_memslots = kvm.get_nr_memslots();
                Ok(KvmContext { kvm, max_memslots })
            }

            Some(c) => Err(Error::KvmCap(*c)),
        }
    }

    pub fn fd(&self) -> &Kvm {
        &self.kvm
    }

    /// Get the maximum number of memory slots reported by this KVM context.
    pub fn max_memslots(&self) -> usize {
        self.max_memslots
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;

    use super::*;

    #[test]
    fn test_kvm_context() {
        use std::os::unix::fs::MetadataExt;
        use std::os::unix::io::{AsRawFd, FromRawFd};

        let c = KvmContext::new().unwrap();

        assert!(c.max_memslots() >= 32);

        let kvm = Kvm::new().unwrap();
        let f = unsafe { File::from_raw_fd(kvm.as_raw_fd()) };
        let m1 = f.metadata().unwrap();
        let m2 = File::open("/dev/kvm").unwrap().metadata().unwrap();

        assert_eq!(m1.dev(), m2.dev());
        assert_eq!(m1.ino(), m2.ino());
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(test)]

extern crate test;
extern crate xi_rope;

use test::Bencher;
use xi_rope::rope::Rope;

fn build_triangle(n: usize) -> String {
    let mut s = String::new();
    let mut line = String::new();
    for _ in 0..n {
        s += &line;
        s += "\n";
        line += "a";
    }
    s
}

fn build_short_lines(n: usize) -> String {
    let line = "match s.as_bytes()[minsplit - 1..splitpoint].iter().rposition(|&c| c == b'\n') {";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

fn build_few_big_lines(size: usize) -> String {
    let mut s = String::with_capacity(size * 10 + 20);
    for _ in 0..10 {
        for _ in 0..size {
            s += "a";
        }
        s += "\n";
    }
    s
}

#[bench]
fn benchmark_file_load_short_lines(b: &mut Bencher) {
    let text = build_short_lines(50_000);
    b.iter(|| {
        Rope::from(&text);
    });
}

#[bench]
fn benchmark_file_load_few_big_lines(b: &mut Bencher) {
    let text = build_few_big_lines(1_000_000);
    b.iter(|| {
        Rope::from(&text);
    });
}

#[bench]
fn benchmark_char_insertion_one_line_edit(b: &mut Bencher) {
    let mut text = Rope::from("b".repeat(100));
    let mut offset = 100;
    b.iter(|| {
        text.edit(offset..=offset, "a");
        offset += 1;
    });
}

#[bench]
fn benchmark_paste_into_line(b: &mut Bencher) {
    let mut text = Rope::from(build_short_lines(50_000));
    let insertion = "a".repeat(50);
    let mut offset = 100;
    b.iter(|| {
        text.edit(offset..=offset, &insertion);
        offset += 150;
    });
}

#[bench]
fn benchmark_insert_newline(b: &mut Bencher) {
    let mut text = Rope::from(build_few_big_lines(1_000_000));
    let mut offset = 1000;
    b.iter(|| {
        text.edit(offset..=offset, "\n");
        offset += 1001;
    });
}

#[bench]
fn benchmark_overwrite_into_line(b: &mut Bencher) {
    let mut text = Rope::from(build_short_lines(50_000));
    let mut offset = 100;
    let insertion = "a".repeat(50);
    b.iter(|| {
        // TODO: if the method runs too quickly, this may generate a fault
        // since there's an upper limit to how many times this can run.
        text.edit(offset..=offset + 20, &insertion);
        offset += 30;
    });
}

#[bench]
fn benchmark_triangle_concat_inplace(b: &mut Bencher) {
    let mut text = Rope::from("");
    let insertion = build_triangle(10_000);
    let insertion_len = insertion.len();
    let mut offset = 0;
    b.iter(|| {
        text.edit(offset..=offset, &insertion);
        offset += insertion_len;
    });
}
<commit_msg>Reduce memory use of triangle_concat benchmark<commit_after>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(test)]

extern crate test;
extern crate xi_rope;

use test::Bencher;
use xi_rope::rope::Rope;

fn build_triangle(n: usize) -> String {
    let mut s = String::new();
    let mut line = String::new();
    for _ in 0..n {
        s += &line;
        s += "\n";
        line += "a";
    }
    s
}

fn build_short_lines(n: usize) -> String {
    let line = "match s.as_bytes()[minsplit - 1..splitpoint].iter().rposition(|&c| c == b'\n') {";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

fn build_few_big_lines(size: usize) -> String {
    let mut s = String::with_capacity(size * 10 + 20);
    for _ in 0..10 {
        for _ in 0..size {
            s += "a";
        }
        s += "\n";
    }
    s
}

#[bench]
fn benchmark_file_load_short_lines(b: &mut Bencher) {
    let text = build_short_lines(50_000);
    b.iter(|| {
        Rope::from(&text);
    });
}

#[bench]
fn benchmark_file_load_few_big_lines(b: &mut Bencher) {
    let text = build_few_big_lines(1_000_000);
    b.iter(|| {
        Rope::from(&text);
    });
}

#[bench]
fn benchmark_char_insertion_one_line_edit(b: &mut Bencher) {
    let mut text = Rope::from("b".repeat(100));
    let mut offset = 100;
    b.iter(|| {
        text.edit(offset..=offset, "a");
        offset += 1;
    });
}

#[bench]
fn benchmark_paste_into_line(b: &mut Bencher) {
    let mut text = Rope::from(build_short_lines(50_000));
    let insertion = "a".repeat(50);
    let mut offset = 100;
    b.iter(|| {
        text.edit(offset..=offset, &insertion);
        offset += 150;
    });
}

#[bench]
fn benchmark_insert_newline(b: &mut Bencher) {
    let mut text = Rope::from(build_few_big_lines(1_000_000));
    let mut offset = 1000;
    b.iter(|| {
        text.edit(offset..=offset, "\n");
        offset += 1001;
    });
}

#[bench]
fn benchmark_overwrite_into_line(b: &mut Bencher) {
    let mut text = Rope::from(build_short_lines(50_000));
    let mut offset = 100;
    let insertion = "a".repeat(50);
    b.iter(|| {
        // TODO: if the method runs too quickly, this may generate a fault
        // since there's an upper limit to how many times this can run.
        text.edit(offset..=offset + 20, &insertion);
        offset += 30;
    });
}

#[bench]
fn benchmark_triangle_concat_inplace(b: &mut Bencher) {
    let mut text = Rope::from("");
    let insertion = build_triangle(3000);
    let insertion_len = insertion.len();
    let mut offset = 0;
    b.iter(|| {
        text.edit(offset..=offset, &insertion);
        offset += insertion_len;
    });
}
<|endoftext|>


<commit_before>use std::io::{self, BufRead, BufReader, BufWriter, Write};

use serde_json::Value;

use crate::protocol::{
    read_message, write_error_response, write_notification, write_success_response,
    write_success_result, ErrorCodes, Message, NotificationMessage, RequestMessage, ResponseError,
};

use crate::{Error, Result};

#[derive(PartialEq)]
enum State {
    Initialized,
    ShuttingDown,
}

struct ServerContext {
    state: State,
    // True when the previous text document has errors.
    has_error: bool,
    // Set when `exit` notification is received.
    exit_code: Option<i32>,
}

impl ServerContext {
    fn new() -> ServerContext {
        ServerContext {
            state: State::Initialized,
            has_error: false,
            exit_code: None,
        }
    }
}

fn create_server_capabilities() -> lsp_types::ServerCapabilities {
    let options = lsp_types::TextDocumentSyncOptions {
        open_close: Some(true),
        change: Some(lsp_types::TextDocumentSyncKind::Full),
        will_save: Some(true),
        will_save_wait_until: Some(false),
        save: None,
    };

    let text_document_sync = lsp_types::TextDocumentSyncCapability::Options(options);

    lsp_types::ServerCapabilities {
        text_document_sync: Some(text_document_sync),
        hover_provider: None,
        completion_provider: None,
        signature_help_provider: None,
        definition_provider: None,
        type_definition_provider: None,
        implementation_provider: None,
        references_provider: None,
        document_highlight_provider: None,
        document_symbol_provider: None,
        workspace_symbol_provider: None,
        code_action_provider: None,
        code_lens_provider: None,
        document_formatting_provider: None,
        document_range_formatting_provider: None,
        document_on_type_formatting_provider: None,
        rename_provider: None,
        color_provider: None,
        folding_range_provider: None,
        execute_command_provider: None,
        workspace: None,
    }
}

// Requests

fn handle_request(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    msg: RequestMessage,
) -> Result<()> {
    let id = msg.id;
    let method = msg.method.as_str();

    let res = match method {
        "initialize" => initialize_request(),
        "shutdown" => shutdown_request(ctx),
        _ => unimplemented!(),
    };
    match res {
        Ok(res) => write_success_response(writer, id, res)?,
        Err(error) => write_error_response(writer, id, error)?,
    }
    Ok(())
}

type MessageResult<T> = std::result::Result<T, ResponseError>;

fn initialize_request() -> MessageResult<Value> {
    // The server has been initialized already.
    let error_message = "Unexpected initialize message".to_owned();
    Err(ResponseError::new(
        ErrorCodes::ServerNotInitialized,
        error_message,
    ))
}

fn shutdown_request(ctx: &mut ServerContext) -> MessageResult<Value> {
    ctx.state = State::ShuttingDown;
    Ok(Value::Null)
}

// Notifications

fn get_params<P: serde::de::DeserializeOwned>(params: Value) -> Result<P> {
    serde_json::from_value::<P>(params).map_err(|err| Error::ProtocolError(err.to_string()))
}

fn handle_notification(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    msg: NotificationMessage,
) -> Result<()> {
    let method = msg.method.as_str();
    eprintln!("Got notification: {}", method);

    use lsp_types::notification::*;
    match msg.method.as_str() {
        Exit::METHOD => exit_notification(ctx),
        DidOpenTextDocument::METHOD => {
            get_params(msg.params).and_then(|params| did_open_text_document(writer, ctx, params))
        }
        DidChangeTextDocument::METHOD => {
            get_params(msg.params).and_then(|params| did_change_text_document(writer, ctx, params))
        }
        _ => unimplemented!(),
    }
}

fn publish_diagnotics(
    writer: &mut impl Write,
    params: lsp_types::PublishDiagnosticsParams,
) -> Result<()> {
    // TODO: Don't use unwrap().
    let params = serde_json::to_value(&params).unwrap();
    write_notification(writer, "textDocument/publishDiagnostics", params)
}

fn _dbg_print_ast(ast: &mojom_parser::MojomFile) {
    for stmt in &ast.stmts {
        match stmt {
            mojom_parser::Statement::Interface(ref intr) => {
                let (line, col) = intr.name.start_pos().line_col();
                eprintln!("{}:{}: name: {}", line, col, intr.name.as_str());
            }
            _ => (),
        };
    }
}

fn _check_syntax(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    uri: lsp_types::Url,
    input: &str,
) -> Result<()> {
    match mojom_parser::parse(input) {
        Ok(ast) => {
            _dbg_print_ast(&ast);
            let params = lsp_types::PublishDiagnosticsParams {
                uri: uri,
                diagnostics: vec![],
            };
            publish_diagnotics(writer, params)?;
            ctx.has_error = false;
        }
        Err(err) => {
            // Convert error location.
            let (start, end) = match err.line_col {
                mojom_parser::LineColLocation::Pos((line, col)) => {
                    let start = lsp_types::Position {
                        line: line as u64 - 1,
                        character: col as u64 - 1,
                    };
                    // ???
                    let end = lsp_types::Position {
                        line: line as u64 - 1,
                        character: col as u64 - 1,
                    };
                    (start, end)
                }
                mojom_parser::LineColLocation::Span(start, end) => {
                    // `start` and `end` are tuples like (line, col).
                    let start = lsp_types::Position {
                        line: start.0 as u64 - 1,
                        character: start.1 as u64 - 1,
                    };
                    let end = lsp_types::Position {
                        line: end.0 as u64 - 1,
                        character: end.1 as u64 - 1,
                    };
                    (start, end)
                }
            };
            let range = lsp_types::Range {
                start: start,
                end: end,
            };
            let diagostic = lsp_types::Diagnostic {
                range: range,
                severity: None,
                code: None,
                source: None,
                message: "Syntax error".to_owned(),
                related_information: None,
            };
            let params = lsp_types::PublishDiagnosticsParams {
                uri: uri,
                diagnostics: vec![diagostic],
            };
            publish_diagnotics(writer, params)?;
            ctx.has_error = true;
        }
    }
    Ok(())
}

fn exit_notification(ctx: &mut ServerContext) -> Result<()> {
    // https://microsoft.github.io/language-server-protocol/specification#exit
    if ctx.state == State::ShuttingDown {
        ctx.exit_code = Some(0);
    } else {
        ctx.exit_code = Some(1);
    }
    Ok(())
}

fn did_open_text_document(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    params: lsp_types::DidOpenTextDocumentParams,
) -> Result<()> {
    let uri = params.text_document.uri.clone();
    _check_syntax(writer, ctx, uri, &params.text_document.text)
}

fn did_change_text_document(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    params: lsp_types::DidChangeTextDocumentParams,
) -> Result<()> {
    let uri = params.text_document.uri.clone();
    let content = params
        .content_changes
        .iter()
        .map(|i| i.text.to_owned())
        .collect::<Vec<_>>();
    let res = content.join("");
    _check_syntax(writer, ctx, uri, &res)
}

// Initialization

fn initialize(
    reader: &mut impl BufRead,
    writer: &mut impl Write,
) -> Result<lsp_types::InitializeParams> {
    let message = read_message(reader)?;

    let (id, params) = match message {
        Message::Request(req) => req.cast::<lsp_types::request::Initialize>()?,
        _ => {
            // TODO: Gracefully handle `exit` and `shutdown` messages.
            let error_message = format!("Expected initialize message but got {:?}", message);
            return Err(Error::ProtocolError(error_message));
        }
    };

    let capabilities = create_server_capabilities();
    let res = lsp_types::InitializeResult {
        capabilities: capabilities,
    };
    write_success_result(writer, id, res)?;

    let message = read_message(reader)?;
    match message {
        Message::Notofication(notif) => notif.cast::<lsp_types::notification::Initialized>()?,
        _ => {
            let error_message = format!("Expected initialized message but got {:?}", message);
            return Err(Error::ProtocolError(error_message));
        }
    };

    Ok(params)
}

// Returns exit code.
pub fn start() -> Result<i32> {
    let mut reader = BufReader::new(io::stdin());
    let mut writer = BufWriter::new(io::stdout());

    let _params = initialize(&mut reader, &mut writer)?;

    let mut ctx = ServerContext::new();

    loop {
        eprintln!("Reading message...");
        let message = read_message(&mut reader)?;
        match message {
            Message::Request(request) => handle_request(&mut writer, &mut ctx, request)?,
            Message::Notofication(notification) => {
                handle_notification(&mut writer, &mut ctx, notification)?
            }
            _ => unimplemented!(),
        };

        if let Some(exit_code) = ctx.exit_code {
            return Ok(exit_code);
        }
    }
}
<commit_msg>server: Accept some notifications<commit_after>use std::io::{self, BufRead, BufReader, BufWriter, Write};

use serde_json::Value;

use crate::protocol::{
    read_message, write_error_response, write_notification, write_success_response,
    write_success_result, ErrorCodes, Message, NotificationMessage, RequestMessage, ResponseError,
};

use crate::{Error, Result};

#[derive(PartialEq)]
enum State {
    Initialized,
    ShuttingDown,
}

struct ServerContext {
    state: State,
    // True when the previous text document has errors.
    has_error: bool,
    // Set when `exit` notification is received.
    exit_code: Option<i32>,
}

impl ServerContext {
    fn new() -> ServerContext {
        ServerContext {
            state: State::Initialized,
            has_error: false,
            exit_code: None,
        }
    }
}

fn create_server_capabilities() -> lsp_types::ServerCapabilities {
    let options = lsp_types::TextDocumentSyncOptions {
        open_close: Some(true),
        change: Some(lsp_types::TextDocumentSyncKind::Full),
        will_save: None,
        will_save_wait_until: None,
        save: None,
    };

    let text_document_sync = lsp_types::TextDocumentSyncCapability::Options(options);

    lsp_types::ServerCapabilities {
        text_document_sync: Some(text_document_sync),
        hover_provider: None,
        completion_provider: None,
        signature_help_provider: None,
        definition_provider: None,
        type_definition_provider: None,
        implementation_provider: None,
        references_provider: None,
        document_highlight_provider: None,
        document_symbol_provider: None,
        workspace_symbol_provider: None,
        code_action_provider: None,
        code_lens_provider: None,
        document_formatting_provider: None,
        document_range_formatting_provider: None,
        document_on_type_formatting_provider: None,
        rename_provider: None,
        color_provider: None,
        folding_range_provider: None,
        execute_command_provider: None,
        workspace: None,
    }
}

// Requests

fn handle_request(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    msg: RequestMessage,
) -> Result<()> {
    let id = msg.id;
    let method = msg.method.as_str();

    let res = match method {
        "initialize" => initialize_request(),
        "shutdown" => shutdown_request(ctx),
        _ => unimplemented!(),
    };
    match res {
        Ok(res) => write_success_response(writer, id, res)?,
        Err(error) => write_error_response(writer, id, error)?,
    }
    Ok(())
}

type MessageResult<T> = std::result::Result<T, ResponseError>;

fn initialize_request() -> MessageResult<Value> {
    // The server has been initialized already.
    let error_message = "Unexpected initialize message".to_owned();
    Err(ResponseError::new(
        ErrorCodes::ServerNotInitialized,
        error_message,
    ))
}

fn shutdown_request(ctx: &mut ServerContext) -> MessageResult<Value> {
    ctx.state = State::ShuttingDown;
    Ok(Value::Null)
}

// Notifications

fn get_params<P: serde::de::DeserializeOwned>(params: Value) -> Result<P> {
    serde_json::from_value::<P>(params).map_err(|err| Error::ProtocolError(err.to_string()))
}

fn do_nothing() -> Result<()> {
    Ok(())
}

fn handle_notification(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    msg: NotificationMessage,
) -> Result<()> {
    let method = msg.method.as_str();
    eprintln!("Got notification: {}", method);

    use lsp_types::notification::*;
    match msg.method.as_str() {
        Exit::METHOD => exit_notification(ctx),
        DidOpenTextDocument::METHOD => {
            get_params(msg.params).and_then(|params| did_open_text_document(writer, ctx, params))
        }
        DidChangeTextDocument::METHOD => {
            get_params(msg.params).and_then(|params| did_change_text_document(writer, ctx, params))
        }
        // Accept following notifications but do nothing.
        DidChangeConfiguration::METHOD => do_nothing(),
        WillSaveTextDocument::METHOD => do_nothing(),
        DidSaveTextDocument::METHOD => do_nothing(),
        // Intentionally crash for unsupported notifications.
        _ => {
            panic!(format!("Notification `{}` isn't supported yet", msg.method.as_str()));
        }
    }
}

fn publish_diagnotics(
    writer: &mut impl Write,
    params: lsp_types::PublishDiagnosticsParams,
) -> Result<()> {
    // TODO: Don't use unwrap().
    let params = serde_json::to_value(&params).unwrap();
    write_notification(writer, "textDocument/publishDiagnostics", params)
}

fn _dbg_print_ast(ast: &mojom_parser::MojomFile) {
    for stmt in &ast.stmts {
        match stmt {
            mojom_parser::Statement::Interface(ref intr) => {
                let (line, col) = intr.name.start_pos().line_col();
                eprintln!("{}:{}: name: {}", line, col, intr.name.as_str());
            }
            _ => (),
        };
    }
}

fn _check_syntax(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    uri: lsp_types::Url,
    input: &str,
) -> Result<()> {
    match mojom_parser::parse(input) {
        Ok(ast) => {
            _dbg_print_ast(&ast);
            let params = lsp_types::PublishDiagnosticsParams {
                uri: uri,
                diagnostics: vec![],
            };
            publish_diagnotics(writer, params)?;
            ctx.has_error = false;
        }
        Err(err) => {
            // Convert error location.
            let (start, end) = match err.line_col {
                mojom_parser::LineColLocation::Pos((line, col)) => {
                    let start = lsp_types::Position {
                        line: line as u64 - 1,
                        character: col as u64 - 1,
                    };
                    // ???
                    let end = lsp_types::Position {
                        line: line as u64 - 1,
                        character: col as u64 - 1,
                    };
                    (start, end)
                }
                mojom_parser::LineColLocation::Span(start, end) => {
                    // `start` and `end` are tuples like (line, col).
                    let start = lsp_types::Position {
                        line: start.0 as u64 - 1,
                        character: start.1 as u64 - 1,
                    };
                    let end = lsp_types::Position {
                        line: end.0 as u64 - 1,
                        character: end.1 as u64 - 1,
                    };
                    (start, end)
                }
            };
            let range = lsp_types::Range {
                start: start,
                end: end,
            };
            let diagostic = lsp_types::Diagnostic {
                range: range,
                severity: Some(lsp_types::DiagnosticSeverity::Error),
                code: Some(lsp_types::NumberOrString::Number(1)),
                source: Some("mojomlsp".to_owned()),
                message: "Syntax error".to_owned(),
                related_information: None,
            };
            let params = lsp_types::PublishDiagnosticsParams {
                uri: uri,
                diagnostics: vec![diagostic],
            };
            publish_diagnotics(writer, params)?;
            ctx.has_error = true;
        }
    }
    Ok(())
}

fn exit_notification(ctx: &mut ServerContext) -> Result<()> {
    // https://microsoft.github.io/language-server-protocol/specification#exit
    if ctx.state == State::ShuttingDown {
        ctx.exit_code = Some(0);
    } else {
        ctx.exit_code = Some(1);
    }
    Ok(())
}

fn did_open_text_document(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    params: lsp_types::DidOpenTextDocumentParams,
) -> Result<()> {
    let uri = params.text_document.uri.clone();
    _check_syntax(writer, ctx, uri, &params.text_document.text)
}

fn did_change_text_document(
    writer: &mut impl Write,
    ctx: &mut ServerContext,
    params: lsp_types::DidChangeTextDocumentParams,
) -> Result<()> {
    let uri = params.text_document.uri.clone();
    let content = params
        .content_changes
        .iter()
        .map(|i| i.text.to_owned())
        .collect::<Vec<_>>();
    let res = content.join("");
    _check_syntax(writer, ctx, uri, &res)
}

// Initialization

fn initialize(
    reader: &mut impl BufRead,
    writer: &mut impl Write,
) -> Result<lsp_types::InitializeParams> {
    let message = read_message(reader)?;

    let (id, params) = match message {
        Message::Request(req) => req.cast::<lsp_types::request::Initialize>()?,
        _ => {
            // TODO: Gracefully handle `exit` and `shutdown` messages.
            let error_message = format!("Expected initialize message but got {:?}", message);
            return Err(Error::ProtocolError(error_message));
        }
    };

    let capabilities = create_server_capabilities();
    let res = lsp_types::InitializeResult {
        capabilities: capabilities,
    };
    write_success_result(writer, id, res)?;

    let message = read_message(reader)?;
    match message {
        Message::Notofication(notif) => notif.cast::<lsp_types::notification::Initialized>()?,
        _ => {
            let error_message = format!("Expected initialized message but got {:?}", message);
            return Err(Error::ProtocolError(error_message));
        }
    };

    Ok(params)
}

// Returns exit code.
pub fn start() -> Result<i32> {
    let mut reader = BufReader::new(io::stdin());
    let mut writer = BufWriter::new(io::stdout());

    let _params = initialize(&mut reader, &mut writer)?;

    let mut ctx = ServerContext::new();

    loop {
        eprintln!("Reading message...");
        let message = read_message(&mut reader)?;
        match message {
            Message::Request(request) => handle_request(&mut writer, &mut ctx, request)?,
            Message::Notofication(notification) => {
                handle_notification(&mut writer, &mut ctx, notification)?
            }
            _ => unimplemented!(),
        };

        if let Some(exit_code) = ctx.exit_code {
            return Ok(exit_code);
        }
    }
}
<|endoftext|>


<commit_before>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq, Eq)]
pub enum Token<'a> {
  Eof,
  Bang,
  Dollar,
  LeftParen,
  RightParen,
  Spread,
  Colon,
  Equals,
  At,
  LeftBracket,
  RightBracket,
  LeftBrace,
  RightBrace,
  Pipe,
  Name(&'a str),
  Int(&'a str),
  Float(&'a str),
  String(&'a str),
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// Int:   (+|-)?(0|[1-9][0-9]*)
// Float: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // Integer part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Token::Bang))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Token::Dollar))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Token::LeftParen))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Token::RightParen))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Token::Colon))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Token::Equals))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Token::At))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Token::LeftBracket))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Token::RightBracket))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Token::LeftBrace))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Token::RightBrace))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Token::Pipe))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Token::Spread))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Token::Name(&self.input[self.lo..self.hi])))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(Token::Int(&self.input[self.lo..self.hi]))),
            (true, true) => Some(Ok(Token::Float(&self.input[self.lo..self.hi]))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(Token::String(&self.input[self.lo..self.hi]))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

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

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    test_with_lex(input, Token::String(expeced));
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Token::Name("name1"));
    test_next_token(&mut lexer, Token::Name("name2"));
    test_next_token(&mut lexer, Token::String("simple"));
    test_next_token(&mut lexer, Token::String("  white space   "));
    test_next_token(&mut lexer, Token::Name("other_name"));
    test_next_token(&mut lexer, Token::Eof);
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, Token::Int("-9"));
    test_next_token(&mut lexer, Token::Int("0"));
    test_next_token(&mut lexer, Token::Int("9"));
    test_next_token(&mut lexer, Token::Int("-0"));
    test_next_token(&mut lexer, Token::Int("-9"));
    test_next_token(&mut lexer, Token::Int("1234"));
    test_next_token(&mut lexer, Token::Int("-1234"));
    test_next_token(&mut lexer, Token::Float("0.0"));
    test_next_token(&mut lexer, Token::Float("-0.0"));
    test_next_token(&mut lexer, Token::Float("1.0"));
    test_next_token(&mut lexer, Token::Float("-1.012"));
    test_next_token(&mut lexer, Token::Float("-0.101"));
    test_next_token(&mut lexer, Token::Float("1.0e2"));
    test_next_token(&mut lexer, Token::Float("-1.0E2"));
    test_next_token(&mut lexer, Token::Float("0.00e-002"));
    test_next_token(&mut lexer, Token::Float("-0.00E+002"));
    test_next_token(&mut lexer, Token::Float("9.1E+0"));
    test_next_token(&mut lexer, Token::Eof);
    assert_eq!(None, lexer.next());
  }
}
<commit_msg>feat: add location to token.<commit_after>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token<'a> {
  Eof(usize, usize),
  Bang(usize, usize),
  Dollar(usize, usize),
  LeftParen(usize, usize),
  RightParen(usize, usize),
  Spread(usize, usize),
  Colon(usize, usize),
  Equals(usize, usize),
  At(usize, usize),
  LeftBracket(usize, usize),
  RightBracket(usize, usize),
  LeftBrace(usize, usize),
  RightBrace(usize, usize),
  Pipe(usize, usize),
  Name(usize, usize, &'a str),
  Int(usize, usize, i64),
  Float(usize, usize, f64),
  String(usize, usize, &'a str),
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// Int:   (+|-)?(0|[1-9][0-9]*)
// Float: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // Integer part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof(self.lo, self.hi)));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Token::Bang(self.lo, self.hi)))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Token::Dollar(self.lo, self.hi)))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Token::LeftParen(self.lo, self.hi)))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Token::RightParen(self.lo, self.hi)))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Token::Colon(self.lo, self.hi)))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Token::Equals(self.lo, self.hi)))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Token::At(self.lo, self.hi)))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Token::LeftBracket(self.lo, self.hi)))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Token::RightBracket(self.lo, self.hi)))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Token::LeftBrace(self.lo, self.hi)))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Token::RightBrace(self.lo, self.hi)))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Token::Pipe(self.lo, self.hi)))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Token::Spread(self.lo, self.hi)))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Token::Name(self.lo, self.hi, &self.input[self.lo..self.hi])))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(Token::Int(self.lo, self.hi, self.input[self.lo..self.hi].parse().unwrap()))),
            (true, true) => Some(Ok(Token::Float(self.lo, self.hi, self.input[self.lo..self.hi].parse().unwrap()))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(Token::String(self.lo, self.hi, &self.input[self.lo..self.hi]))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

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

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    let len = expeced.len();
    test_with_lex(input, Token::String(1, len + 1, expeced))
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Token::Name(5, 10,"name1"));
    test_next_token(&mut lexer, Token::Name(14,19,"name2"));
    test_next_token(&mut lexer, Token::String(23,29,"simple"));
    test_next_token(&mut lexer, Token::String(32,48,"  white space   "));
    test_next_token(&mut lexer, Token::Name(50,60,"other_name"));
    test_next_token(&mut lexer, Token::Eof(50,60));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, Token::Int(0,2,    -9));
    test_next_token(&mut lexer, Token::Int(3,4,     0));
    test_next_token(&mut lexer, Token::Int(5,6,     9));
    test_next_token(&mut lexer, Token::Int(7,9,    -0));
    test_next_token(&mut lexer, Token::Int(10,12,  -9));
    test_next_token(&mut lexer, Token::Int(13,17,   1234));
    test_next_token(&mut lexer, Token::Int(18,23,  -1234));
    test_next_token(&mut lexer, Token::Float(24,27, 0.0));
    test_next_token(&mut lexer, Token::Float(28,32,-0.0));
    test_next_token(&mut lexer, Token::Float(33,36, 1.0));
    test_next_token(&mut lexer, Token::Float(37,43,-1.012));
    test_next_token(&mut lexer, Token::Float(44,50,-0.101));
    test_next_token(&mut lexer, Token::Float(51,56, 1.0e2));
    test_next_token(&mut lexer, Token::Float(57,63,-1.0E2));
    test_next_token(&mut lexer, Token::Float(64,73, 0.00e-002));
    test_next_token(&mut lexer, Token::Float(74,84,-0.00E+002));
    test_next_token(&mut lexer, Token::Float(85,91, 9.1E+0));
    test_next_token(&mut lexer, Token::Eof(85,91));
    assert_eq!(None, lexer.next());
  }
}
<|endoftext|>


<commit_before>const _PAGE_SIZE: usize = 0x1000;

pub struct _Page<'a> {
    current_page: Option<&'a _Page<'a>>,
    next_object_offset: i32,
    exclusive_pages: i32
}

impl<'a> _Page<'a> {

    pub unsafe fn reset(&mut self) {
        *self.get_extension_page_location() = Option::None;
        self.next_object_offset = 0;
        self.exclusive_pages = 0;

        // currentPage = this;
        self.current_page = std::mem::transmute::<&mut _Page, Option<&'a _Page<'a>>>(self);
    }

    pub unsafe fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        match self.current_page { None => true, _ => false }
    }

    unsafe fn get_extension_page_location(&self) -> *mut Option<&'a _Page<'a>> {

        // Convert self to u8 pointer
        let u8_ptr = std::mem::transmute::<*const _Page, *const u8>(&*self);

        // Advance one page size so we are past the end of our page
        let ptr_advanced_by_page_size = u8_ptr.offset(_PAGE_SIZE as isize);

        // Convert to *_Page?
        let ptr_next_page = std::mem::transmute::<*const u8, *mut Option<&'a _Page<'a>>>(ptr_advanced_by_page_size);

        // Go back one pointer size
        let ptr_at_end_of_page = ptr_next_page.offset(-1);

        // Convert to mutable pointer to the optional extension page
        &mut *ptr_at_end_of_page
    }

    unsafe fn _get_next_object(&self) -> *mut u8 {
        let u8_ptr = std::mem::transmute::<*const _Page, *const u8>(&*self);
        let offset_pointer = u8_ptr.offset(self.next_object_offset as isize);
        offset_pointer as *mut u8
    }

    unsafe fn _set_next_object(&mut self, object: *const u8) {
        let self_ptr = std::mem::transmute::<*const _Page, *const u8>(&*self);
        self.next_object_offset = (object as usize - self_ptr as usize) as i32;
    }

    unsafe fn deallocate_extensions(&mut self) {
        unimplemented!()
    }
}

#[test]
fn test_page() {

    unsafe {

        // Allocate a page
        let memory = std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE) );
        assert_ne!(memory, std::ptr::null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut*std::mem::transmute::<*mut u8, *mut _Page>(memory);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, 0);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!(page.current_page.unwrap().next_object_offset, 0);
        assert_eq!(page.current_page.unwrap().exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);

    }
}<commit_msg>Some _Page methods<commit_after>const _PAGE_SIZE: usize = 0x1000;

pub struct _Page<'a> {
    current_page: *mut _Page<'a>,
    next_object_offset: i32,
    exclusive_pages: i32
}

impl<'a> _Page<'a> {

    pub unsafe fn reset(&mut self) {
        *(self.get_extension_page_location() as *mut *const _Page) = std::ptr::null();
        self.next_object_offset = 0;
        self.exclusive_pages = 0;

        // currentPage = this;
        self.current_page = &mut *self;
    }

    pub unsafe fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    unsafe fn get_extension_page_location(&self) -> usize {

        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = self_location + _PAGE_SIZE;

        // Go back one pointer size
        location_behind_page - std::mem::size_of::<*const _Page>()
    }

    unsafe fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    unsafe fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    unsafe fn get_next_exclusive_page_location(&self) -> usize  {
        self.get_extension_page_location() - (self.exclusive_pages as usize + 1) * std::mem::size_of::<*const _Page>()
    }

    pub unsafe fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if !std::ptr::eq(self, self.current_page) {

            // We're already known to be full, so we delegate to the current page
            let new_object = (*self.current_page).allocate_raw(size, align);

            // Possibly our current page was also full so we propagate back the new current page
            let allocating_page = _Page::get_page(new_object);
            if !std::ptr::eq(allocating_page, self.current_page) && (!allocating_page.is_oversized()) {
                self.current_page = allocating_page;
            }
            return new_object;
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let next_location = (location + align - 1) & !(align - 1);
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        let gross_size = std::mem::size_of::<_Page>() + size + std::mem::size_of::<*const _Page>();
        if gross_size > _PAGE_SIZE {
            if self.get_next_location() >= self.get_extension_page_location() {

                // Allocate an extension page with default size
                let extension_page = self.allocate_extension_page();

                // Try again with the new extension page
                return extension_page.allocate_raw(size, align);
            }

            // We allocate oversized objects directly.
            let memory = std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(size + std::mem::size_of::<_Page>(), _PAGE_SIZE) );

            // Initialize a _Page object at the page start
            let page = memory as *mut _Page<'a>;
            (*page).reset();

            // Oversized pages have no current_page
            (*page).current_page = std::ptr::null_mut();

            *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
            self.exclusive_pages = self.exclusive_pages + 1;
            return page.offset(1) as *mut u8;
        }

        // So we're not oversized. Create extension page and let it allocate.
        self.allocate_extension_page().allocate_raw(size, align)
    }

    unsafe fn allocate_extension_page(&mut self) -> &'a mut _Page<'a> {

        // Allocate a page
        let memory = std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE) );

        // Initialize a _Page object at the page start
        let page = memory as *mut _Page<'a>;
        (*page).reset();
        *(self.get_extension_page_location() as *mut *const _Page) = page;
        self.current_page = page;
        &mut *page
    }

    pub unsafe fn get_page(address: *mut u8) -> &'a mut _Page<'a> {
        &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page)
    }

    unsafe fn deallocate_extensions(&mut self) {
        unimplemented!()
    }
}

#[test]
fn test_page() {

    unsafe {

        // Allocate a page
        let memory = std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE) );
        assert_ne!(memory, std::ptr::null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, 0);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!((*(page.current_page)).next_object_offset, 0);
        assert_eq!((*(page.current_page)).exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);

    }
}<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey = ec::EcKey::private_key_from_pem(ecc_data)
        .ok()
        .expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    // Private keys generated by OpenSSL have variable size but we only handle
    // constant size. Serialization is done in big endian so if the size is less
    // than 32 bytes, we need to prepend with null bytes.
    // If the size is 33 bytes, this means the serialized BigInt is negative.
    // Any other size is invalid.
    let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
    let priv_key_vec = pkey.private_key().to_vec();
    let key_len = priv_key_vec.len();

    assert!(
        key_len <= 33,
        "Invalid private key (too big): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );

    // Copy OpenSSL generated key to our vec, starting from the end
    let mut output_vec = [0u8; 32];
    let min_key_len = std::cmp::min(key_len, 32);
    output_vec[32 - min_key_len..].copy_from_slice(&priv_key_vec[key_len - min_key_len..]);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&output_vec).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert)
        .ok()
        .expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<commit_msg>Fix clippy warnings.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey =
        ec::EcKey::private_key_from_pem(ecc_data).expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    // Private keys generated by OpenSSL have variable size but we only handle
    // constant size. Serialization is done in big endian so if the size is less
    // than 32 bytes, we need to prepend with null bytes.
    // If the size is 33 bytes, this means the serialized BigInt is negative.
    // Any other size is invalid.
    let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
    let priv_key_vec = pkey.private_key().to_vec();
    let key_len = priv_key_vec.len();

    assert!(
        key_len <= 33,
        "Invalid private key (too big): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );

    // Copy OpenSSL generated key to our vec, starting from the end
    let mut output_vec = [0u8; 32];
    let min_key_len = std::cmp::min(key_len, 32);
    output_vec[32 - min_key_len..].copy_from_slice(&priv_key_vec[key_len - min_key_len..]);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&output_vec).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert).expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<|endoftext|>


<commit_before>extern crate cc;

use std::path::Path;

fn main() {
    let dir_path = Path::new("vendor/tree-sitter/src/runtime");

    let source_filenames = [
      "get_changed_ranges.c",
      "language.c",
      "lexer.c",
      "node.c",
      "parser.c",
      "parser.c",
      "stack.c",
      "subtree.c",
      "tree_cursor.c",
      "tree.c",
      "utf16.c",
    ];

    let mut config = cc::Build::new();
    config.include("vendor/tree-sitter/src");
    config.include("vendor/tree-sitter/include");
    config.include("vendor/tree-sitter/externals/utf8proc");
    config.flag_if_supported("-Wno-unused-parameter");

    for source_filename in source_filenames.iter() {
        let source_path = dir_path.join(Path::new(&source_filename));
        config.file(&source_path.to_str().unwrap());
    }

    config.compile("libruntime.a")
}
<commit_msg>Compile tree-sitter sources in c99 mode<commit_after>extern crate cc;

use std::path::Path;

fn main() {
    let dir_path = Path::new("vendor/tree-sitter/src/runtime");

    let source_filenames = [
      "get_changed_ranges.c",
      "language.c",
      "lexer.c",
      "node.c",
      "parser.c",
      "parser.c",
      "stack.c",
      "subtree.c",
      "tree_cursor.c",
      "tree.c",
      "utf16.c",
    ];

    let mut config = cc::Build::new();
    config.include("vendor/tree-sitter/src");
    config.include("vendor/tree-sitter/include");
    config.include("vendor/tree-sitter/externals/utf8proc");
    config.flag_if_supported("-std=c99");
    config.flag_if_supported("-Wno-unused-parameter");

    for source_filename in source_filenames.iter() {
        let source_path = dir_path.join(Path::new(&source_filename));
        config.file(&source_path.to_str().unwrap());
    }

    config.compile("libruntime.a")
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    gcc::Config::new()
                .file("src/predicates.c")
				.opt_level(2)
                .compile("libpredicates.a");
}
<commit_msg>Fixed formatting<commit_after>extern crate gcc;

fn main() {
    gcc::Config::new()
                .file("src/predicates.c")
		.opt_level(2)
                .compile("libpredicates.a");
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::fs;
use std::path::Path;

use core::{Package, Profiles};
use util::{CargoResult, human, ChainError, Config};
use ops::{self, Layout, Context, BuildConfig, Kind, Unit};

pub struct CleanOptions<'a> {
    pub spec: &'a [String],
    pub target: Option<&'a str>,
    pub config: &'a Config,
    pub release: bool,
}

/// Cleans the project from build artifacts.
pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
    let root = try!(Package::for_path(manifest_path, opts.config));
    let target_dir = opts.config.target_dir(&root);

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    //
    // Note that we don't bother grabbing a lock here as we're just going to
    // blow it all away anyway.
    if opts.spec.is_empty() {
        let target_dir = target_dir.into_path_unlocked();
        return rm_rf(&target_dir);
    }

    let (resolve, packages) = try!(ops::fetch(manifest_path, opts.config));

    let dest = if opts.release {"release"} else {"debug"};
    let host_layout = try!(Layout::new(opts.config, &root, None, dest));
    let target_layout = match opts.target {
        Some(target) => {
            Some(try!(Layout::new(opts.config, &root, Some(target), dest)))
        }
        None => None,
    };

    let cx = try!(Context::new(&resolve, &packages, opts.config,
                               host_layout, target_layout,
                               BuildConfig::default(),
                               root.manifest().profiles()));

    // resolve package specs and remove the corresponding packages
    for spec in opts.spec {
        // Translate the spec to a Package
        let pkgid = try!(resolve.query(spec));
        let pkg = try!(packages.get(&pkgid));

        // And finally, clean everything out!
        for target in pkg.targets() {
            for kind in [Kind::Host, Kind::Target].iter() {
                let layout = cx.layout(&pkg, *kind);
                try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
                try!(rm_rf(&layout.build(&pkg)));
                let Profiles {
                    ref release, ref dev, ref test, ref bench, ref doc,
                    ref custom_build, ref test_deps, ref bench_deps,
                } = *root.manifest().profiles();
                let profiles = [release, dev, test, bench, doc, custom_build,
                                test_deps, bench_deps];
                for profile in profiles.iter() {
                    let unit = Unit {
                        pkg: &pkg,
                        target: target,
                        profile: profile,
                        kind: *kind,
                    };
                    let root = cx.out_dir(&unit);
                    for filename in try!(cx.target_filenames(&unit)).iter() {
                        try!(rm_rf(&root.join(&filename)));
                    }
                }
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> CargoResult<()> {
    let m = fs::metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        try!(fs::remove_dir_all(path).chain_error(|| {
            human("could not remove build directory")
        }));
    } else if m.is_ok() {
        try!(fs::remove_file(path).chain_error(|| {
            human("failed to remove build artifact")
        }));
    }
    Ok(())
}
<commit_msg>Auto merge of #2704 - alexcrichton:clean-no-fetch, r=brson<commit_after>use std::default::Default;
use std::fs;
use std::path::Path;

use core::{Package, Profiles};
use core::registry::PackageRegistry;
use util::{CargoResult, human, ChainError, Config};
use ops::{self, Layout, Context, BuildConfig, Kind, Unit};

pub struct CleanOptions<'a> {
    pub spec: &'a [String],
    pub target: Option<&'a str>,
    pub config: &'a Config,
    pub release: bool,
}

/// Cleans the project from build artifacts.
pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
    let root = try!(Package::for_path(manifest_path, opts.config));
    let target_dir = opts.config.target_dir(&root);

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    //
    // Note that we don't bother grabbing a lock here as we're just going to
    // blow it all away anyway.
    if opts.spec.is_empty() {
        let target_dir = target_dir.into_path_unlocked();
        return rm_rf(&target_dir);
    }

    let mut registry = PackageRegistry::new(opts.config);
    let resolve = try!(ops::resolve_pkg(&mut registry, &root, opts.config));
    let packages = ops::get_resolved_packages(&resolve, registry);

    let dest = if opts.release {"release"} else {"debug"};
    let host_layout = try!(Layout::new(opts.config, &root, None, dest));
    let target_layout = match opts.target {
        Some(target) => {
            Some(try!(Layout::new(opts.config, &root, Some(target), dest)))
        }
        None => None,
    };

    let cx = try!(Context::new(&resolve, &packages, opts.config,
                               host_layout, target_layout,
                               BuildConfig::default(),
                               root.manifest().profiles()));

    // resolve package specs and remove the corresponding packages
    for spec in opts.spec {
        // Translate the spec to a Package
        let pkgid = try!(resolve.query(spec));
        let pkg = try!(packages.get(&pkgid));

        // And finally, clean everything out!
        for target in pkg.targets() {
            for kind in [Kind::Host, Kind::Target].iter() {
                let layout = cx.layout(&pkg, *kind);
                try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
                try!(rm_rf(&layout.build(&pkg)));
                let Profiles {
                    ref release, ref dev, ref test, ref bench, ref doc,
                    ref custom_build, ref test_deps, ref bench_deps,
                } = *root.manifest().profiles();
                let profiles = [release, dev, test, bench, doc, custom_build,
                                test_deps, bench_deps];
                for profile in profiles.iter() {
                    let unit = Unit {
                        pkg: &pkg,
                        target: target,
                        profile: profile,
                        kind: *kind,
                    };
                    let root = cx.out_dir(&unit);
                    for filename in try!(cx.target_filenames(&unit)).iter() {
                        try!(rm_rf(&root.join(&filename)));
                    }
                }
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> CargoResult<()> {
    let m = fs::metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        try!(fs::remove_dir_all(path).chain_error(|| {
            human("could not remove build directory")
        }));
    } else if m.is_ok() {
        try!(fs::remove_file(path).chain_error(|| {
            human("failed to remove build artifact")
        }));
    }
    Ok(())
}
<|endoftext|>