<commit_before>#[doc = "Rust wrappers around the raw JS apis"];

#[allow(non_implicitly_copyable_typarams)];

use bg = jsapi::bindgen;
use core::libc::types::os::arch::c95::{size_t, c_uint};
use core::libc::c_char;
use core::hashmap::linear::LinearMap;
use jsapi::*;
use jsapi::bindgen::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use core::ptr::null;
use result;
use result_obj;
use core::str::raw::from_c_str;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

pub impl rt_rsrc {
    fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        return new_runtime(JS_Init(default_heapsize))
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut LinearMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn finalize(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut LinearMap::new()
    }
}

pub impl Cx {
    fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut LinearMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_imm_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            })
        })
    }

    fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        *(self.classes.find(&s).expect(error_msg))
    }

    unsafe fn get_cx_private(@self) -> *() {
        cast::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::reinterpret_cast(&data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut LinearMap<~str, jsobj>
}

pub impl Compartment {
    fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(&mut self.global_funcs, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(&mut self.global_props, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&copy proto_name).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    fn get_global_proto(@mut self, name: ~str) -> jsobj {
        *(self.global_protos.get(&name))
    }
    fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            unsafe {
                let cbuf = cast::reinterpret_cast(&buf);
                bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        })
    }
}

#[cfg(test)]
pub mod test {
    use rt;
    use global;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<commit_msg>Remove unused imports.<commit_after>#[doc = "Rust wrappers around the raw JS apis"];

#[allow(non_implicitly_copyable_typarams)];

use bg = jsapi::bindgen;
use core::libc::types::os::arch::c95::{size_t, c_uint};
use core::libc::c_char;
use core::hashmap::linear::LinearMap;
use jsapi::*;
use jsapi::bindgen::*;
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSVAL_NULL;
use ERR;
use name_pool::*;
use core::ptr::null;
use result;
use result_obj;
use core::str::raw::from_c_str;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = @rt_rsrc;

pub struct rt_rsrc {
    ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return @rt_rsrc {
        ptr: p
    }
}

pub impl rt_rsrc {
    fn cx(@self) -> @Cx {
        unsafe {
            new_context(JS_NewContext(self.ptr, default_stacksize as size_t), self)
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        return new_runtime(JS_Init(default_heapsize))
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    ptr: *JSContext,
    rt: rt,
    classes: @mut LinearMap<~str, @JSClass>,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn finalize(&self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> @Cx {
    return @Cx {
        ptr: ptr,
        rt: rt,
        classes: @mut LinearMap::new()
    }
}

pub impl Cx {
    fn rooted_obj(@self, obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        unsafe {
            JS_AddObjectRoot(self.ptr, ptr::to_unsafe_ptr(&jsobj.ptr));
        }
        jsobj
    }

    fn set_default_options_and_version(@self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(@self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    fn set_version(@self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    fn set_logging_error_reporter(@self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    fn set_error_reporter(@self, reportfn: *u8) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    fn new_compartment(@self,
                       globclsfn: &fn(@mut NamePool) -> JSClass)
                    -> Result<@mut Compartment,()> {
        unsafe {
            let np = NamePool();
            let globcls = @globclsfn(np);
            let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
            result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
                let compartment = @mut Compartment {
                    cx: self,
                    name_pool: np,
                    global_funcs: ~[],
                    global_props: ~[],
                    global_class: globcls,
                    global_obj: self.rooted_obj(globobj),
                    global_protos: @mut LinearMap::new()
                };
                self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
                Ok(compartment)
            })
        }
    }

    fn evaluate_script(@self, glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_imm_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: JSVal = JSVAL_NULL;
                debug!("Evaluating script from %s with bytes %?", filename, bytes);
                unsafe {
                    if JS_EvaluateScript(self.ptr, glob.ptr,
                                         bytes_ptr, bytes_len as c_uint,
                                         filename_cstr, line_num as c_uint,
                                         ptr::to_unsafe_ptr(&rval)) == ERR {
                        debug!("...err!");
                        Err(())
                    } else {
                        // we could return the script result but then we'd have
                        // to root it and so forth and, really, who cares?
                        debug!("...ok!");
                        Ok(())
                    }
                }
            })
        })
    }

    fn lookup_class_name(@self, s: ~str) ->  @JSClass {
        // FIXME: expect should really take a lambda...
        let error_msg = fmt!("class %s not found in class table", s);
        *(self.classes.find(&s).expect(error_msg))
    }

    unsafe fn get_cx_private(@self) -> *() {
        cast::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(@self, data: *()) {
        JS_SetContextPrivate(self.ptr, cast::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(@self, obj: *JSObject) -> *() {
        cast::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(@self, obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, cast::reinterpret_cast(&data));
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at %s:%?: %s\n", fname, lineno, msg);
    }
}

// ___________________________________________________________________________
// compartment

pub struct Compartment {
    cx: @Cx,
    name_pool: @mut NamePool,
    global_funcs: ~[@~[JSFunctionSpec]],
    global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: @mut LinearMap<~str, jsobj>
}

pub impl Compartment {
    fn define_functions(@mut self,
                        specfn: &fn(@mut NamePool) -> ~[JSFunctionSpec])
                     -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(&mut self.global_funcs, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_properties(@mut self, specfn: &fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(&mut self.global_props, specvec);
        vec::as_imm_buf(*specvec, |specs, _len| {
            unsafe {
                result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
            }
        })
    }
    fn define_property(@mut self,
                       name: ~str,
                       value: JSVal,
                       getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        unsafe {
            result(JS_DefineProperty(self.cx.ptr,
                                     self.global_obj.ptr,
                                     self.add_name(name),
                                     value,
                                     getter,
                                     setter,
                                     attrs))
        }
    }
    fn new_object(@mut self, class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        unsafe {
            let classptr = self.cx.lookup_class_name(class_name);
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, &*classptr, proto, parent));
            result_obj(obj)
        }
    }
    fn new_object_with_proto(@mut self, class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = self.global_protos.find(&copy proto_name).expect(
            fmt!("new_object_with_proto: expected to find %s in the proto \
                  table", proto_name));
        unsafe {
            let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                      proto.ptr, parent));
            result_obj(obj)
        }
    }
    fn get_global_proto(@mut self, name: ~str) -> jsobj {
        *(self.global_protos.get(&name))
    }
    fn stash_global_proto(@mut self, name: ~str, proto: jsobj) {
        let global_protos = self.global_protos;
        if !global_protos.insert(name, proto) {
            fail!(~"Duplicate global prototype registered; you're gonna have a bad time.")
        }
    }
    fn register_class(@mut self, class_fn: &fn(x: @mut Compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { from_c_str(classptr.name) },
            classptr) {
            fail!(~"Duplicate JSClass registered; you're gonna have a bad time.")
        }
    }
    fn add_name(@mut self, name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

pub type jsobj = @jsobj_rsrc;

pub struct jsobj_rsrc {
    cx: @Cx,
    cxptr: *JSContext,
    ptr: *JSObject,
}

#[unsafe_destructor]
impl Drop for jsobj_rsrc {
    fn finalize(&self) {
        unsafe {
            JS_RemoveObjectRoot(self.cxptr, ptr::to_unsafe_ptr(&self.ptr));
        }
    }
}

impl jsobj_rsrc {
    fn new_object(&self, cx: @Cx, cxptr: *JSContext, ptr: *JSObject) -> jsobj {
        return @jsobj_rsrc {
            cx: cx,
            cxptr: cxptr,
            ptr: ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

pub trait to_jsstr {
    fn to_jsstr(self, cx: @Cx) -> *JSString;
}

impl to_jsstr for ~str {
    fn to_jsstr(self, cx: @Cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            unsafe {
                let cbuf = cast::reinterpret_cast(&buf);
                bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
            }
        })
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::super::global;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<|endoftext|>


<commit_before>#![feature(core,io,path)]
extern crate atomicwrites;
extern crate tempdir;

use std::{fs,path};
use std::io::{Read,Write};
use atomicwrites::{AtomicFile,AllowOverwrite,DisallowOverwrite};
use tempdir::TempDir;

fn get_tmp() -> path::PathBuf {
    TempDir::new_in(".", "atomicwrites-test").unwrap().into_path()
}

#[test]
fn test_simple_allow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, AllowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv.as_slice(), "HELLO");
}

#[test]
fn test_simple_disallow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv.as_slice(), "HELLO");
}

#[test]
fn test_allowed_pathtypes() {
    AtomicFile::new(&"haha", DisallowOverwrite);
    AtomicFile::new(&path::Path::new("haha"), DisallowOverwrite);
    AtomicFile::new(&path::PathBuf::new("haha"), DisallowOverwrite);
}

#[test]
fn test_unicode() {
    let dmitri = "Дмитрий";
    let greeting = format!("HELLO {}", dmitri);

    let tmpdir = get_tmp();
    let path = tmpdir.join(dmitri);

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| {
        f.write_all(greeting.as_bytes())
    }).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv, greeting);
}
<commit_msg>Add more tests regarding allowed types<commit_after>#![feature(core,io,path)]
extern crate atomicwrites;
extern crate tempdir;

use std::{fs,path};
use std::io::{Read,Write};
use atomicwrites::{AtomicFile,AllowOverwrite,DisallowOverwrite};
use tempdir::TempDir;

fn get_tmp() -> path::PathBuf {
    TempDir::new_in(".", "atomicwrites-test").unwrap().into_path()
}

#[test]
fn test_simple_allow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, AllowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv.as_slice(), "HELLO");
}

#[test]
fn test_simple_disallow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv.as_slice(), "HELLO");
}

#[test]
fn test_allowed_pathtypes() {
    AtomicFile::new("haha", DisallowOverwrite);
    AtomicFile::new(&"haha", DisallowOverwrite);
    AtomicFile::new(&path::Path::new("haha"), DisallowOverwrite);
    AtomicFile::new(&path::PathBuf::new("haha"), DisallowOverwrite);
}

#[test]
fn test_unicode() {
    let dmitri = "Дмитрий";
    let greeting = format!("HELLO {}", dmitri);

    let tmpdir = get_tmp();
    let path = tmpdir.join(dmitri);

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| {
        f.write_all(greeting.as_bytes())
    }).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv, greeting);
}
<|endoftext|>


<commit_before>use crate::{Point, Size};

/// A `Rectangle` is normally expressed as a top-left corner and a size
///
/// # Examples
/// ```rust
/// let rectangle = Rectangle::new((0., 5.),(10., 7.));
///
/// assert_eq!(rectangle.x(), 0.);
/// assert_eq!(rectangle.y(), 5.);
/// assert_eq!(rectangle.width(), 10.);
/// assert_eq!(rectangle.height(), 7.);
/// ```
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Rectangle {
    /// Position of the rectangle.
    position: Point,

    size: Size,
}

impl Rectangle {
    /// Create a new rectangle with the given parameters.
    pub fn new(position: impl Into<Point>, size: impl Into<Size>) -> Self {
        Rectangle {
            position: position.into(),
            size: size.into(),
        }
    }

    /// Gets x.
    pub fn x(&self) -> f64 {
        self.position.x()
    }

    /// Sets x.
    pub fn set_x(&mut self, x: impl Into<f64>) {
        self.position.set_x(x);
    }

    /// Gets y.
    pub fn y(&self) -> f64 {
        self.position.y()
    }

    /// Sets y.
    pub fn set_y(&mut self, y: impl Into<f64>) {
        self.position.set_y(y);
    }

    /// Gets position as `Point`.
    pub fn position(&self) -> Point {
        self.position
    }

    /// Sets position.
    pub fn set_position(&mut self, position: impl Into<Point>) {
        self.position = position.into();
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.size.width()
    }

    /// Sets the width.
    pub fn set_width(&mut self, width: impl Into<f64>) {
        self.size.set_width(width.into());
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.size.height()
    }

    /// Sets the height.
    pub fn set_height(&mut self, height: impl Into<f64>) {
        self.size.set_height(height.into());
    }

    /// Gets the size with width and height.
    pub fn size(&self) -> Size {
        self.size
    }

    /// Sets the size with width and height.
    pub fn set_size(&mut self, width: impl Into<f64>, height: impl Into<f64>) {
        self.size.set_width(width.into());
        self.size.set_height(height.into());
    }

    /// Checks if this rect contains the given `point`.
    pub fn contains(&self, point: impl Into<Point>) -> bool {
        let point: Point = point.into();
        point.x() >= self.x()
            && point.x() <= self.x() + self.width()
            && point.y() >= self.y()
            && point.y() <= self.y() + self.height()
    }

    /// Checks if this rect contains the given `rect`.
    pub fn contains_rect(&self, rect: &Rectangle) -> bool {
        let p1 = rect.position();
        let p2 = (p1.x() + rect.width(), p1.y() + rect.height());
        self.contains(p1) && self.contains(p2)
    }

    /// Checks if this rect intersects with the given `rect`.
    pub fn intersects(&self, rect: &Rectangle) -> bool {
        !(rect.x() > (self.x() + self.width())
            || self.x() > (rect.x() + rect.width())
            || rect.y() > (self.y() + self.height())
            || self.y() > (rect.y() + rect.height()))
    }

    /// Joins this rectangle with another one, the result is
    /// a rectangle in which the two parents fit.
    pub fn join_with_rectangle(&mut self, other: &Rectangle) {
        if other.x() < self.x() {
            self.set_width(self.width() + self.x() - other.x());
            self.set_x(other.x());
        }
        if other.y() < self.y() {
            self.set_height(self.height() + self.y() - other.y());
            self.set_y(other.y());
        }
        if other.x() + other.width() > self.x() + self.width() {
            self.set_width(other.x() + other.width() - self.x());
        }
        if other.y() + other.height() > self.y() + self.height() {
            self.set_height(other.y() + other.height() - self.y());
        }
    }

    /// Extends this rectangle to cover the given point.
    pub fn join_with_point(&mut self, point: &Point) {
        if point.x() < self.x() {
            self.set_width(self.width() + self.x() - point.x());
            self.set_x(point.x());
        }
        if point.y() < self.y() {
            self.set_height(self.height() + self.y() - point.y());
            self.set_y(point.y());
        }
        if point.x() > self.x() + self.width() {
            self.set_width(point.x() - self.x());
        }
        if point.y() > self.y() + self.height() {
            self.set_height(point.y() - self.y());
        }
    }

    /// Box itself inside another rectangle
    pub fn box_into(&mut self, _box: Rectangle) {
        if self.x() < _box.x() {
            self.set_width(self.width() - (_box.x() - self.x()));
            self.set_x(_box.x());
        }
        if self.y() < _box.y() {
            self.set_height(self.height() - (_box.y() - self.y()));
            self.set_y(_box.y());
        }
        if self.x() + self.width() > _box.x() + _box.width() {
            self.set_width(_box.width() - _box.x() + self.x());
        }
        if self.y() + self.height() > _box.y() + _box.height() {
            self.set_height(_box.height() - _box.y() + self.y());
        }
    }
}

// --- Conversions ---

impl From<(Point, Size)> for Rectangle {
    fn from(t: (Point, Size)) -> Self {
        Rectangle::new(t.0, t.1)
    }
}

impl From<(i32, i32, i32, i32)> for Rectangle {
    fn from(t: (i32, i32, i32, i32)) -> Self {
        Rectangle::new((t.0 as f64, t.1 as f64), (t.2 as f64, t.3 as f64))
    }
}

impl From<(f64, f64, f64, f64)> for Rectangle {
    fn from(t: (f64, f64, f64, f64)) -> Self {
        Rectangle::new((t.0, t.1), (t.2, t.3))
    }
}

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

    #[test]
    fn test_new() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        assert_eq!(rect.x(), 5.0);
        assert_eq!(rect.y(), 10.0);
        assert_eq!(rect.width(), 20.0);
        assert_eq!(rect.height(), 30.0);
    }

    #[test]
    fn test_contains() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Contains point in its origin
        let p = Point::new(5.0, 10.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains point in its bottom right corner
        let p = Point::new(25.0, 40.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains normal point
        let p = Point::new(15.0, 15.0);
        assert!(rect.contains(p), "{:?}", p);

        // Doesn't contain point with x out of rect
        let p = Point::new(30.0, 15.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with y out of rect
        let p = Point::new(15.0, 50.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with both x and y out of rect
        let p = Point::new(30.0, 40.0);
        assert!(!rect.contains(p), "{:?}", p);
    }

    #[test]
    fn test_contains_rect() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Contains itself
        let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect on one of its edges
        let r = Rectangle::new((5.0, 20.0), (10.0, 20.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect on two of its edges
        let r = Rectangle::new((5.0, 10.0), (10.0, 20.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect completly inside
        let r = Rectangle::new((10.0, 20.0), (5.0, 10.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Does not contain rect partially inside
        let r = Rectangle::new((20.0, 25.0), (20.0, 30.0));
        assert!(!rect.contains_rect(&r), "{:?}", r);

        // Does not contain rect completely outside
        let r = Rectangle::new((50.0, 100.0), (20.0, 30.0));
        assert!(!rect.contains_rect(&r), "{:?}", r);
    }

    #[test]
    fn test_intersects() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Intersects with itself
        let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with origin on right edge
        let r = Rectangle::new((25.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with end on left edge
        let r = Rectangle::new((-15.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with origin on bottom edge
        let r = Rectangle::new((5.0, 40.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with end on upper edge
        let r = Rectangle::new((5.0, -20.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin is further
        // right than origin + width of this rect
        let r = Rectangle::new((30.0, 10.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where end + width is further
        // left than origin of this rect
        let r = Rectangle::new((-20.0, 10.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin is further
        // down than origin + width of this rect
        let r = Rectangle::new((5.0, 50.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin + height is further
        // up than origin of this rect
        let r = Rectangle::new((5.0, -30.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);
    }
}
<commit_msg>rename _box<commit_after>use crate::{Point, Size};

/// A `Rectangle` is normally expressed as a top-left corner and a size
///
/// # Examples
/// ```rust
/// let rectangle = Rectangle::new((0., 5.),(10., 7.));
///
/// assert_eq!(rectangle.x(), 0.);
/// assert_eq!(rectangle.y(), 5.);
/// assert_eq!(rectangle.width(), 10.);
/// assert_eq!(rectangle.height(), 7.);
/// ```
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Rectangle {
    /// Position of the rectangle.
    position: Point,

    size: Size,
}

impl Rectangle {
    /// Create a new rectangle with the given parameters.
    pub fn new(position: impl Into<Point>, size: impl Into<Size>) -> Self {
        Rectangle {
            position: position.into(),
            size: size.into(),
        }
    }

    /// Gets x.
    pub fn x(&self) -> f64 {
        self.position.x()
    }

    /// Sets x.
    pub fn set_x(&mut self, x: impl Into<f64>) {
        self.position.set_x(x);
    }

    /// Gets y.
    pub fn y(&self) -> f64 {
        self.position.y()
    }

    /// Sets y.
    pub fn set_y(&mut self, y: impl Into<f64>) {
        self.position.set_y(y);
    }

    /// Gets position as `Point`.
    pub fn position(&self) -> Point {
        self.position
    }

    /// Sets position.
    pub fn set_position(&mut self, position: impl Into<Point>) {
        self.position = position.into();
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.size.width()
    }

    /// Sets the width.
    pub fn set_width(&mut self, width: impl Into<f64>) {
        self.size.set_width(width.into());
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.size.height()
    }

    /// Sets the height.
    pub fn set_height(&mut self, height: impl Into<f64>) {
        self.size.set_height(height.into());
    }

    /// Gets the size with width and height.
    pub fn size(&self) -> Size {
        self.size
    }

    /// Sets the size with width and height.
    pub fn set_size(&mut self, width: impl Into<f64>, height: impl Into<f64>) {
        self.size.set_width(width.into());
        self.size.set_height(height.into());
    }

    /// Checks if this rect contains the given `point`.
    pub fn contains(&self, point: impl Into<Point>) -> bool {
        let point: Point = point.into();
        point.x() >= self.x()
            && point.x() <= self.x() + self.width()
            && point.y() >= self.y()
            && point.y() <= self.y() + self.height()
    }

    /// Checks if this rect contains the given `rect`.
    pub fn contains_rect(&self, rect: &Rectangle) -> bool {
        let p1 = rect.position();
        let p2 = (p1.x() + rect.width(), p1.y() + rect.height());
        self.contains(p1) && self.contains(p2)
    }

    /// Checks if this rect intersects with the given `rect`.
    pub fn intersects(&self, rect: &Rectangle) -> bool {
        !(rect.x() > (self.x() + self.width())
            || self.x() > (rect.x() + rect.width())
            || rect.y() > (self.y() + self.height())
            || self.y() > (rect.y() + rect.height()))
    }

    /// Joins this rectangle with another one, the result is
    /// a rectangle in which the two parents fit.
    pub fn join_with_rectangle(&mut self, other: &Rectangle) {
        if other.x() < self.x() {
            self.set_width(self.width() + self.x() - other.x());
            self.set_x(other.x());
        }
        if other.y() < self.y() {
            self.set_height(self.height() + self.y() - other.y());
            self.set_y(other.y());
        }
        if other.x() + other.width() > self.x() + self.width() {
            self.set_width(other.x() + other.width() - self.x());
        }
        if other.y() + other.height() > self.y() + self.height() {
            self.set_height(other.y() + other.height() - self.y());
        }
    }

    /// Extends this rectangle to cover the given point.
    pub fn join_with_point(&mut self, point: &Point) {
        if point.x() < self.x() {
            self.set_width(self.width() + self.x() - point.x());
            self.set_x(point.x());
        }
        if point.y() < self.y() {
            self.set_height(self.height() + self.y() - point.y());
            self.set_y(point.y());
        }
        if point.x() > self.x() + self.width() {
            self.set_width(point.x() - self.x());
        }
        if point.y() > self.y() + self.height() {
            self.set_height(point.y() - self.y());
        }
    }

    /// Box itself inside another rectangle
    pub fn box_into(&mut self, container: Rectangle) {
        if self.x() < container.x() {
            self.set_width(self.width() - (container.x() - self.x()));
            self.set_x(container.x());
        }
        if self.y() < container.y() {
            self.set_height(self.height() - (container.y() - self.y()));
            self.set_y(container.y());
        }
        if self.x() + self.width() > container.x() + container.width() {
            self.set_width(container.width() - container.x() + self.x());
        }
        if self.y() + self.height() > container.y() + container.height() {
            self.set_height(container.height() - container.y() + self.y());
        }
    }
}

// --- Conversions ---

impl From<(Point, Size)> for Rectangle {
    fn from(t: (Point, Size)) -> Self {
        Rectangle::new(t.0, t.1)
    }
}

impl From<(i32, i32, i32, i32)> for Rectangle {
    fn from(t: (i32, i32, i32, i32)) -> Self {
        Rectangle::new((t.0 as f64, t.1 as f64), (t.2 as f64, t.3 as f64))
    }
}

impl From<(f64, f64, f64, f64)> for Rectangle {
    fn from(t: (f64, f64, f64, f64)) -> Self {
        Rectangle::new((t.0, t.1), (t.2, t.3))
    }
}

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

    #[test]
    fn test_new() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        assert_eq!(rect.x(), 5.0);
        assert_eq!(rect.y(), 10.0);
        assert_eq!(rect.width(), 20.0);
        assert_eq!(rect.height(), 30.0);
    }

    #[test]
    fn test_contains() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Contains point in its origin
        let p = Point::new(5.0, 10.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains point in its bottom right corner
        let p = Point::new(25.0, 40.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains normal point
        let p = Point::new(15.0, 15.0);
        assert!(rect.contains(p), "{:?}", p);

        // Doesn't contain point with x out of rect
        let p = Point::new(30.0, 15.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with y out of rect
        let p = Point::new(15.0, 50.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with both x and y out of rect
        let p = Point::new(30.0, 40.0);
        assert!(!rect.contains(p), "{:?}", p);
    }

    #[test]
    fn test_contains_rect() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Contains itself
        let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect on one of its edges
        let r = Rectangle::new((5.0, 20.0), (10.0, 20.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect on two of its edges
        let r = Rectangle::new((5.0, 10.0), (10.0, 20.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Contains rect completly inside
        let r = Rectangle::new((10.0, 20.0), (5.0, 10.0));
        assert!(rect.contains_rect(&r), "{:?}", r);

        // Does not contain rect partially inside
        let r = Rectangle::new((20.0, 25.0), (20.0, 30.0));
        assert!(!rect.contains_rect(&r), "{:?}", r);

        // Does not contain rect completely outside
        let r = Rectangle::new((50.0, 100.0), (20.0, 30.0));
        assert!(!rect.contains_rect(&r), "{:?}", r);
    }

    #[test]
    fn test_intersects() {
        let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));

        // Intersects with itself
        let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with origin on right edge
        let r = Rectangle::new((25.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with end on left edge
        let r = Rectangle::new((-15.0, 10.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with origin on bottom edge
        let r = Rectangle::new((5.0, 40.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Intersects with rect with end on upper edge
        let r = Rectangle::new((5.0, -20.0), (20.0, 30.0));
        assert!(rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin is further
        // right than origin + width of this rect
        let r = Rectangle::new((30.0, 10.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where end + width is further
        // left than origin of this rect
        let r = Rectangle::new((-20.0, 10.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin is further
        // down than origin + width of this rect
        let r = Rectangle::new((5.0, 50.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);

        // Does not intersect with rect where origin + height is further
        // up than origin of this rect
        let r = Rectangle::new((5.0, -30.0), (20.0, 30.0));
        assert!(!rect.intersects(&r), "{:?}", r);
    }
}
<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    env,
    fmt::{self, Write as _},
    io::Write as _,
    time::{Instant, SystemTime, UNIX_EPOCH},
};

use anyhow::{bail, format_err, Result};

use crate::not_bash::{fs2, pushd, rm_rf, run};

type Unit = &'static str;

pub fn run_metrics() -> Result<()> {
    let mut metrics = Metrics::new()?;
    metrics.measure_build()?;

    {
        let _d = pushd("target/metrics");
        let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
        writeln!(file, "{}", metrics.json())?;
        run!("git add .")?;
        run!("git commit --author='GitHub Action <>' --message='📈' ")?;

        if let Ok(actor) = env::var("GITHUB_ACTOR") {
            let token = env::var("GITHUB_TOKEN").unwrap();
            let repo = format!("https://{}:{}@github.com/rust-analyzer/metrics.git", actor, token);
            run!("git push {}", repo)?;
        }
    }
    eprintln!("{:#?}\n", metrics);
    eprintln!("{}", metrics.json());
    Ok(())
}

impl Metrics {
    fn measure_build(&mut self) -> Result<()> {
        run!("cargo fetch")?;
        rm_rf("./target/release")?;

        let build = Instant::now();
        // run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?;
        let build = build.elapsed();
        self.report("build", build.as_millis() as u64, "ms");
        Ok(())
    }
}

#[derive(Debug)]
struct Metrics {
    host: Host,
    timestamp: SystemTime,
    revision: String,
    metrics: BTreeMap<String, (u64, Unit)>,
}

#[derive(Debug)]
struct Host {
    os: String,
    cpu: String,
    mem: String,
}

impl Metrics {
    fn new() -> Result<Metrics> {
        let host = Host::new()?;
        let timestamp = SystemTime::now();
        let revision = run!("git rev-parse HEAD")?;
        Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
    }

    fn report(&mut self, name: &str, value: u64, unit: Unit) {
        self.metrics.insert(name.into(), (value, unit));
    }

    fn json(&self) -> Json {
        let mut json = Json::default();
        self.to_json(&mut json);
        json
    }
    fn to_json(&self, json: &mut Json) {
        json.begin_object();
        {
            json.field("host");
            self.host.to_json(json);

            json.field("timestamp");
            let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
            json.number(timestamp.as_secs() as f64);

            json.field("revision");
            json.string(&self.revision);

            json.field("metrics");
            json.begin_object();
            {
                for (k, &(value, unit)) in &self.metrics {
                    json.field(k);
                    json.begin_array();
                    {
                        json.number(value as f64);
                        json.string(unit);
                    }
                    json.end_array();
                }
            }
            json.end_object()
        }
        json.end_object();
    }
}

impl Host {
    fn new() -> Result<Host> {
        if cfg!(not(target_os = "linux")) {
            bail!("can only collect metrics on Linux ");
        }

        let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();

        let cpu =
            read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();

        let mem = read_field("/proc/meminfo", "MemTotal:")?;

        return Ok(Host { os, cpu, mem });

        fn read_field<'a>(path: &str, field: &str) -> Result<String> {
            let text = fs2::read_to_string(path)?;

            let line = text
                .lines()
                .find(|it| it.starts_with(field))
                .ok_or_else(|| format_err!("can't parse {}", path))?;
            Ok(line[field.len()..].trim().to_string())
        }
    }
    fn to_json(&self, json: &mut Json) {
        json.begin_object();
        {
            json.field("os");
            json.string(&self.os);

            json.field("cpu");
            json.string(&self.cpu);

            json.field("mem");
            json.string(&self.mem);
        }
        json.end_object();
    }
}

#[derive(Default)]
struct Json {
    object_comma: bool,
    array_comma: bool,
    buf: String,
}

impl Json {
    fn begin_object(&mut self) {
        self.object_comma = false;
        self.buf.push('{');
    }
    fn end_object(&mut self) {
        self.buf.push('}')
    }
    fn begin_array(&mut self) {
        self.array_comma = false;
        self.buf.push('[');
    }
    fn end_array(&mut self) {
        self.buf.push(']')
    }
    fn field(&mut self, name: &str) {
        self.object_comma();
        self.string_token(name);
        self.buf.push(':');
    }
    fn string(&mut self, value: &str) {
        self.array_comma();
        self.string_token(value);
    }
    fn string_token(&mut self, value: &str) {
        self.buf.push('"');
        self.buf.extend(value.escape_default());
        self.buf.push('"');
    }
    fn number(&mut self, value: f64) {
        self.array_comma();
        write!(self.buf, "{}", value).unwrap();
    }

    fn array_comma(&mut self) {
        if self.array_comma {
            self.buf.push(',');
        }
        self.array_comma = true;
    }

    fn object_comma(&mut self) {
        if self.object_comma {
            self.buf.push(',');
        }
        self.object_comma = true;
    }
}

impl fmt::Display for Json {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.buf)
    }
}
<commit_msg>fix syntax<commit_after>use std::{
    collections::BTreeMap,
    env,
    fmt::{self, Write as _},
    io::Write as _,
    time::{Instant, SystemTime, UNIX_EPOCH},
};

use anyhow::{bail, format_err, Result};

use crate::not_bash::{fs2, pushd, rm_rf, run};

type Unit = &'static str;

pub fn run_metrics() -> Result<()> {
    let mut metrics = Metrics::new()?;
    metrics.measure_build()?;

    {
        let _d = pushd("target/metrics");
        let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
        writeln!(file, "{}", metrics.json())?;
        run!("git add .")?;
        run!("git commit --author 'GitHub Action <>' --message '📈' ")?;

        if let Ok(actor) = env::var("GITHUB_ACTOR") {
            let token = env::var("GITHUB_TOKEN").unwrap();
            let repo = format!("https://{}:{}@github.com/rust-analyzer/metrics.git", actor, token);
            run!("git push {}", repo)?;
        }
    }
    eprintln!("{:#?}\n", metrics);
    eprintln!("{}", metrics.json());
    Ok(())
}

impl Metrics {
    fn measure_build(&mut self) -> Result<()> {
        run!("cargo fetch")?;
        rm_rf("./target/release")?;

        let build = Instant::now();
        // run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?;
        let build = build.elapsed();
        self.report("build", build.as_millis() as u64, "ms");
        Ok(())
    }
}

#[derive(Debug)]
struct Metrics {
    host: Host,
    timestamp: SystemTime,
    revision: String,
    metrics: BTreeMap<String, (u64, Unit)>,
}

#[derive(Debug)]
struct Host {
    os: String,
    cpu: String,
    mem: String,
}

impl Metrics {
    fn new() -> Result<Metrics> {
        let host = Host::new()?;
        let timestamp = SystemTime::now();
        let revision = run!("git rev-parse HEAD")?;
        Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
    }

    fn report(&mut self, name: &str, value: u64, unit: Unit) {
        self.metrics.insert(name.into(), (value, unit));
    }

    fn json(&self) -> Json {
        let mut json = Json::default();
        self.to_json(&mut json);
        json
    }
    fn to_json(&self, json: &mut Json) {
        json.begin_object();
        {
            json.field("host");
            self.host.to_json(json);

            json.field("timestamp");
            let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
            json.number(timestamp.as_secs() as f64);

            json.field("revision");
            json.string(&self.revision);

            json.field("metrics");
            json.begin_object();
            {
                for (k, &(value, unit)) in &self.metrics {
                    json.field(k);
                    json.begin_array();
                    {
                        json.number(value as f64);
                        json.string(unit);
                    }
                    json.end_array();
                }
            }
            json.end_object()
        }
        json.end_object();
    }
}

impl Host {
    fn new() -> Result<Host> {
        if cfg!(not(target_os = "linux")) {
            bail!("can only collect metrics on Linux ");
        }

        let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();

        let cpu =
            read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();

        let mem = read_field("/proc/meminfo", "MemTotal:")?;

        return Ok(Host { os, cpu, mem });

        fn read_field<'a>(path: &str, field: &str) -> Result<String> {
            let text = fs2::read_to_string(path)?;

            let line = text
                .lines()
                .find(|it| it.starts_with(field))
                .ok_or_else(|| format_err!("can't parse {}", path))?;
            Ok(line[field.len()..].trim().to_string())
        }
    }
    fn to_json(&self, json: &mut Json) {
        json.begin_object();
        {
            json.field("os");
            json.string(&self.os);

            json.field("cpu");
            json.string(&self.cpu);

            json.field("mem");
            json.string(&self.mem);
        }
        json.end_object();
    }
}

#[derive(Default)]
struct Json {
    object_comma: bool,
    array_comma: bool,
    buf: String,
}

impl Json {
    fn begin_object(&mut self) {
        self.object_comma = false;
        self.buf.push('{');
    }
    fn end_object(&mut self) {
        self.buf.push('}')
    }
    fn begin_array(&mut self) {
        self.array_comma = false;
        self.buf.push('[');
    }
    fn end_array(&mut self) {
        self.buf.push(']')
    }
    fn field(&mut self, name: &str) {
        self.object_comma();
        self.string_token(name);
        self.buf.push(':');
    }
    fn string(&mut self, value: &str) {
        self.array_comma();
        self.string_token(value);
    }
    fn string_token(&mut self, value: &str) {
        self.buf.push('"');
        self.buf.extend(value.escape_default());
        self.buf.push('"');
    }
    fn number(&mut self, value: f64) {
        self.array_comma();
        write!(self.buf, "{}", value).unwrap();
    }

    fn array_comma(&mut self) {
        if self.array_comma {
            self.buf.push(',');
        }
        self.array_comma = true;
    }

    fn object_comma(&mut self) {
        if self.object_comma {
            self.buf.push(',');
        }
        self.object_comma = true;
    }
}

impl fmt::Display for Json {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.buf)
    }
}
<|endoftext|>


<commit_before>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.header.type_ver;
            self.header.type_ver = t as u8 << 4 | version;
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            UtpStream::new(self.socket, other)
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Add `packed` hint for UtpPacketHeader.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    #[packed]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.header.type_ver;
            self.header.type_ver = t as u8 << 4 | version;
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            UtpStream::new(self.socket, other)
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>//! A "mutex" which only supports `try_lock`
//!
//! As a futures library the eventual call to an event loop should be the only
//! thing that ever blocks, so this is assisted with a fast user-space
//! implementation of a lock that can only have a `try_lock` operation.

extern crate core;

use self::core::cell::UnsafeCell;
use self::core::ops::{Deref, DerefMut};
use self::core::sync::atomic::Ordering::{Acquire, Release};
use self::core::sync::atomic::AtomicBool;

/// A "mutex" around a value, similar to `std::sync::Mutex<T>`.
///
/// This lock only supports the `try_lock` operation, however, and does not
/// implement poisoning.
pub struct Lock<T> {
    locked: AtomicBool,
    data: UnsafeCell<T>,
}

/// Sentinel representing an acquired lock through which the data can be
/// accessed.
pub struct TryLock<'a, T: 'a> {
    __ptr: &'a Lock<T>,
}

// The `Lock` structure is basically just a `Mutex<T>`, and these two impls are
// intended to mirror the standard library's corresponding impls for `Mutex<T>`.
//
// If a `T` is sendable across threads, so is the lock, and `T` must be sendable
// across threads to be `Sync` because it allows mutable access from multiple
// threads.
unsafe impl<T: Send> Send for Lock<T> {}
unsafe impl<T: Send> Sync for Lock<T> {}

impl<T> Lock<T> {
    /// Creates a new lock around the given value.
    pub fn new(t: T) -> Lock<T> {
        Lock {
            locked: AtomicBool::new(false),
            data: UnsafeCell::new(t),
        }
    }

    /// Attempts to acquire this lock, returning whether the lock was acquired or
    /// not.
    ///
    /// If `Some` is returned then the data this lock protects can be accessed
    /// through the sentinel. This sentinel allows both mutable and immutable
    /// access.
    ///
    /// If `None` is returned then the lock is already locked, either elsewhere
    /// on this thread or on another thread.
    pub fn try_lock(&self) -> Option<TryLock<T>> {
        if !self.locked.swap(true, Acquire) {
            Some(TryLock { __ptr: self })
        } else {
            None
        }
    }
}

impl<'a, T> Deref for TryLock<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        // The existence of `TryLock` represents that we own the lock, so we
        // can safely access the data here.
        unsafe { &*self.__ptr.data.get() }
    }
}

impl<'a, T> DerefMut for TryLock<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        // The existence of `TryLock` represents that we own the lock, so we
        // can safely access the data here.
        //
        // Additionally, we're the *only* `TryLock` in existence so mutable
        // access should be ok.
        unsafe { &mut *self.__ptr.data.get() }
    }
}

impl<'a, T> Drop for TryLock<'a, T> {
    fn drop(&mut self) {
        self.__ptr.locked.store(false, Release);
    }
}

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

    #[test]
    fn smoke() {
        let a = Lock::new(1);
        let mut a1 = a.try_lock().unwrap();
        assert!(a.try_lock().is_none());
        assert_eq!(*a1, 1);
        *a1 = 2;
        drop(a1);
        assert_eq!(*a.try_lock().unwrap(), 2);
        assert_eq!(*a.try_lock().unwrap(), 2);
    }
}
<commit_msg>Use SeqCst instead of Acquire and Release in Lock.<commit_after>//! A "mutex" which only supports `try_lock`
//!
//! As a futures library the eventual call to an event loop should be the only
//! thing that ever blocks, so this is assisted with a fast user-space
//! implementation of a lock that can only have a `try_lock` operation.

extern crate core;

use self::core::cell::UnsafeCell;
use self::core::ops::{Deref, DerefMut};
use self::core::sync::atomic::Ordering::{SeqCst};
use self::core::sync::atomic::AtomicBool;

/// A "mutex" around a value, similar to `std::sync::Mutex<T>`.
///
/// This lock only supports the `try_lock` operation, however, and does not
/// implement poisoning.
pub struct Lock<T> {
    locked: AtomicBool,
    data: UnsafeCell<T>,
}

/// Sentinel representing an acquired lock through which the data can be
/// accessed.
pub struct TryLock<'a, T: 'a> {
    __ptr: &'a Lock<T>,
}

// The `Lock` structure is basically just a `Mutex<T>`, and these two impls are
// intended to mirror the standard library's corresponding impls for `Mutex<T>`.
//
// If a `T` is sendable across threads, so is the lock, and `T` must be sendable
// across threads to be `Sync` because it allows mutable access from multiple
// threads.
unsafe impl<T: Send> Send for Lock<T> {}
unsafe impl<T: Send> Sync for Lock<T> {}

impl<T> Lock<T> {
    /// Creates a new lock around the given value.
    pub fn new(t: T) -> Lock<T> {
        Lock {
            locked: AtomicBool::new(false),
            data: UnsafeCell::new(t),
        }
    }

    /// Attempts to acquire this lock, returning whether the lock was acquired or
    /// not.
    ///
    /// If `Some` is returned then the data this lock protects can be accessed
    /// through the sentinel. This sentinel allows both mutable and immutable
    /// access.
    ///
    /// If `None` is returned then the lock is already locked, either elsewhere
    /// on this thread or on another thread.
    pub fn try_lock(&self) -> Option<TryLock<T>> {
        if !self.locked.swap(true, SeqCst) {
            Some(TryLock { __ptr: self })
        } else {
            None
        }
    }
}

impl<'a, T> Deref for TryLock<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        // The existence of `TryLock` represents that we own the lock, so we
        // can safely access the data here.
        unsafe { &*self.__ptr.data.get() }
    }
}

impl<'a, T> DerefMut for TryLock<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        // The existence of `TryLock` represents that we own the lock, so we
        // can safely access the data here.
        //
        // Additionally, we're the *only* `TryLock` in existence so mutable
        // access should be ok.
        unsafe { &mut *self.__ptr.data.get() }
    }
}

impl<'a, T> Drop for TryLock<'a, T> {
    fn drop(&mut self) {
        self.__ptr.locked.store(false, SeqCst);
    }
}

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

    #[test]
    fn smoke() {
        let a = Lock::new(1);
        let mut a1 = a.try_lock().unwrap();
        assert!(a.try_lock().is_none());
        assert_eq!(*a1, 1);
        *a1 = 2;
        drop(a1);
        assert_eq!(*a.try_lock().unwrap(), 2);
        assert_eq!(*a.try_lock().unwrap(), 2);
    }
}
<|endoftext|>


<commit_before>use kbdgen::{
    cldr::{Keyboard, *},
    models::{DesktopModes, IsoKey, MobileModes},
    Load, ProjectBundle,
};
use log::{debug, log_enabled};
use snafu::{ResultExt, Snafu};
use snafu_cli_debug::SnafuCliDebug;
use std::{collections::BTreeMap, fs::File, io::BufWriter, path::PathBuf};
use structopt::StructOpt;
use strum::IntoEnumIterator;

#[derive(Debug, StructOpt)]
struct Cli {
    #[structopt(parse(from_os_str))]
    input: PathBuf,

    #[structopt(parse(from_os_str))]
    output: PathBuf,

    #[structopt(flatten)]
    verbose: clap_verbosity_flag::Verbosity,
}

fn main() -> Result<(), Error> {
    let opts = Cli::from_args();
    let _ = opts.verbose.setup_env_logger("kbdgen-to-cldr");

    let bundle = ProjectBundle::load(&opts.input).context(CannotLoad)?;
    if log_enabled!(log::Level::Debug) {
        debug!("Bundle `{}` loaded", opts.input.display());
        let locales = bundle
            .project
            .locales
            .values()
            .map(|l| l.name.as_str())
            .collect::<Vec<_>>();
        debug!("Bundle contains these locales: {:?}", locales);
    }

    bundle
        .layouts
        .iter()
        .map(|(name, layout)| (name, layout_to_cldr(&name, layout, &bundle)))
        .try_for_each(|(name, keyboards)| {
            for (platform, keyboard) in keyboards? {
                let path = &opts.output.join(name).join(platform).with_extension("xml");
                std::fs::create_dir_all(path.parent().unwrap())
                    .context(CannotCreateFile { path })?;
                let file = File::create(path).context(CannotCreateFile { path })?;
                let mut writer = BufWriter::new(file);
                keyboard
                    .write_xml(&mut writer)
                    .context(CannotSerializeXml)?;
            }
            Ok(())
        })
        .context(CannotBeSaved)?;

    Ok(())
}

fn layout_to_cldr(
    name: &str,
    layout: &kbdgen::models::Layout,
    _project: &kbdgen::ProjectBundle,
) -> Result<Vec<(String, Keyboard)>, SavingError> {
    log::debug!("to cldr with you, {}!", name);

    let mut res = vec![];

    if let Some(a) = layout.modes.android.as_ref() {
        log::debug!("android: check");
        res.push((
            String::from("android"),
            mobile_mode_to_keyboard(name, "android", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.ios.as_ref() {
        log::debug!("ios: check");
        res.push((
            String::from("ios"),
            mobile_mode_to_keyboard(name, "ios", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.mobile.as_ref() {
        log::debug!("generic mobile: check");
        res.push((
            String::from("mobile"),
            mobile_mode_to_keyboard(name, "mobile", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.win.as_ref() {
        log::debug!("generic win: check");
        res.push((
            String::from("win"),
            desktop_mode_to_keyboard(name, "win", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.mac.as_ref() {
        log::debug!("generic mac: check");
        res.push((
            String::from("mac"),
            desktop_mode_to_keyboard(name, "mac", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.chrome.as_ref() {
        log::debug!("generic chrome: check");
        res.push((
            String::from("chrome"),
            desktop_mode_to_keyboard(name, "chrome", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.x11.as_ref() {
        log::debug!("generic x11: check");
        res.push((
            String::from("x11"),
            desktop_mode_to_keyboard(name, "x11", a, layout.longpress.as_ref(), layout),
        ));
    }
    if let Some(a) = layout.modes.desktop.as_ref() {
        log::debug!("generic desktop: check");
        res.push((
            String::from("desktop"),
            desktop_mode_to_keyboard(name, "desktop", a, layout.longpress.as_ref(), layout),
        ));
    }

    Ok(res)
}

fn desktop_mode_to_keyboard(
    name: &str,
    target: &str,
    desktop: &DesktopModes,
    long_presses: Option<&BTreeMap<String, String>>,
    layout: &kbdgen::models::Layout,
) -> Keyboard {
    let mut key_maps = vec![];

    for (modifiers, mapping) in desktop {
        let keys = mapping
            .iter()
            .filter_map(|(iso, value)| {
                if let Some(value) = value.as_ref() {
                    Some((iso, value))
                } else {
                    None
                }
            })
            .map(|(iso, value)| {
                let long_press = long_presses.and_then(|l| l.get(value.as_str())).cloned();
                Map {
                    iso: iso.to_string(),
                    to: value.to_string(),
                    transform: None,
                    long_press,
                }
            })
            .collect();

        key_maps.push(KeyMap {
            keys,
            modifiers: Some(modifiers.to_string()),
        })
    }

    Keyboard {
        locale: format!("{}-t-k0-{}", name, target),
        names: vec![Names {
            values: vec![Name {
                value: pick_name_from_display_names(&layout.display_names),
            }],
        }],
        key_maps,
        ..Keyboard::default()
    }
}

fn mobile_mode_to_keyboard(
    name: &str,
    target: &str,
    mobile: &MobileModes,
    long_presses: Option<&BTreeMap<String, String>>,
    layout: &kbdgen::models::Layout,
) -> Keyboard {
    let mut key_maps = vec![];

    for (modifiers, mapping) in mobile {
        let keys = IsoKey::iter()
            .zip(mapping.iter())
            .map(|(iso, value)| {
                let long_press = long_presses.and_then(|l| l.get(value)).cloned();
                Map {
                    iso: iso.to_string(),
                    to: value.to_string(),
                    transform: None,
                    long_press,
                }
            })
            .collect();

        key_maps.push(KeyMap {
            keys,
            modifiers: Some(modifiers.to_string()),
        })
    }

    Keyboard {
        locale: format!("{}-t-k0-{}", name, target),
        names: vec![Names {
            values: vec![Name {
                value: pick_name_from_display_names(&layout.display_names),
            }],
        }],
        key_maps,
        ..Keyboard::default()
    }
}

fn pick_name_from_display_names(names: &BTreeMap<String, String>) -> String {
    names
        .get("en")
        .or_else(|| names.values().next())
        .cloned()
        .unwrap_or_default()
}

#[derive(Snafu, SnafuCliDebug)]
pub enum Error {
    #[snafu(display("Could not load kbdgen bundle"))]
    CannotLoad {
        source: kbdgen::LoadError,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could not write CLDR file"))]
    CannotBeSaved {
        source: SavingError,
        backtrace: snafu::Backtrace,
    },
}

#[derive(Snafu, Debug)]
pub enum SavingError {
    #[snafu(display("Could not create file `{}`", path.display()))]
    CannotCreateFile {
        path: PathBuf,
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could transform to xml"))]
    CannotSerializeXml {
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
}
<commit_msg>Macro all the repetition away<commit_after>use kbdgen::{
    cldr::{Keyboard, *},
    models::{DesktopModes, IsoKey, MobileModes},
    Load, ProjectBundle,
};
use log::{debug, log_enabled};
use snafu::{ResultExt, Snafu};
use snafu_cli_debug::SnafuCliDebug;
use std::{collections::BTreeMap, fs::File, io::BufWriter, path::PathBuf};
use structopt::StructOpt;
use strum::IntoEnumIterator;

#[derive(Debug, StructOpt)]
struct Cli {
    #[structopt(parse(from_os_str))]
    input: PathBuf,

    #[structopt(parse(from_os_str))]
    output: PathBuf,

    #[structopt(flatten)]
    verbose: clap_verbosity_flag::Verbosity,
}

fn main() -> Result<(), Error> {
    let opts = Cli::from_args();
    let _ = opts.verbose.setup_env_logger("kbdgen-to-cldr");

    let bundle = ProjectBundle::load(&opts.input).context(CannotLoad)?;
    if log_enabled!(log::Level::Debug) {
        debug!("Bundle `{}` loaded", opts.input.display());
        let locales = bundle
            .project
            .locales
            .values()
            .map(|l| l.name.as_str())
            .collect::<Vec<_>>();
        debug!("Bundle contains these locales: {:?}", locales);
    }

    bundle
        .layouts
        .iter()
        .map(|(name, layout)| (name, layout_to_cldr(&name, layout, &bundle)))
        .try_for_each(|(name, keyboards)| {
            for (platform, keyboard) in keyboards? {
                let path = &opts.output.join(name).join(platform).with_extension("xml");
                std::fs::create_dir_all(path.parent().unwrap())
                    .context(CannotCreateFile { path })?;
                let file = File::create(path).context(CannotCreateFile { path })?;
                let mut writer = BufWriter::new(file);
                keyboard
                    .write_xml(&mut writer)
                    .context(CannotSerializeXml)?;
            }
            Ok(())
        })
        .context(CannotBeSaved)?;

    Ok(())
}

fn layout_to_cldr(
    name: &str,
    layout: &kbdgen::models::Layout,
    _project: &kbdgen::ProjectBundle,
) -> Result<Vec<(String, Keyboard)>, SavingError> {
    log::debug!("to cldr with you, {}!", name);

    let mut res = vec![];

    macro_rules! mode {
        (mobile: $name:ident) => {
            mode!(mobile_mode_to_keyboard -> $name)
        };
        (desktop: $name:ident) => {
            mode!(desktop_mode_to_keyboard -> $name)
        };
        ($fn:ident -> $name:ident) => {
            if let Some(a) = layout.modes.$name.as_ref() {
                log::debug!("{}: check", stringify!($name));
                res.push((
                    String::from(stringify!($name)),
                    $fn(name, stringify!($name), a, layout.longpress.as_ref(), layout),
                ));
            }
        };
    }

    mode!(mobile: android);
    mode!(mobile: ios);
    mode!(mobile: mobile);
    mode!(desktop: win);
    mode!(desktop: mac);
    mode!(desktop: chrome);
    mode!(desktop: x11);
    mode!(desktop: desktop);

    Ok(res)
}

fn desktop_mode_to_keyboard(
    name: &str,
    target: &str,
    desktop: &DesktopModes,
    long_presses: Option<&BTreeMap<String, String>>,
    layout: &kbdgen::models::Layout,
) -> Keyboard {
    let mut key_maps = vec![];

    for (modifiers, mapping) in desktop {
        let keys = mapping
            .iter()
            .filter_map(|(iso, value)| {
                if let Some(value) = value.as_ref() {
                    Some((iso, value))
                } else {
                    None
                }
            })
            .map(|(iso, value)| {
                let long_press = long_presses.and_then(|l| l.get(value.as_str())).cloned();
                Map {
                    iso: iso.to_string(),
                    to: value.to_string(),
                    transform: None,
                    long_press,
                }
            })
            .collect();

        key_maps.push(KeyMap {
            keys,
            modifiers: Some(modifiers.to_string()),
        })
    }

    Keyboard {
        locale: format!("{}-t-k0-{}", name, target),
        names: vec![Names {
            values: vec![Name {
                value: pick_name_from_display_names(&layout.display_names),
            }],
        }],
        key_maps,
        ..Keyboard::default()
    }
}

fn mobile_mode_to_keyboard(
    name: &str,
    target: &str,
    mobile: &MobileModes,
    long_presses: Option<&BTreeMap<String, String>>,
    layout: &kbdgen::models::Layout,
) -> Keyboard {
    let mut key_maps = vec![];

    for (modifiers, mapping) in mobile {
        let keys = IsoKey::iter()
            .zip(mapping.iter())
            .map(|(iso, value)| {
                let long_press = long_presses.and_then(|l| l.get(value)).cloned();
                Map {
                    iso: iso.to_string(),
                    to: value.to_string(),
                    transform: None,
                    long_press,
                }
            })
            .collect();

        key_maps.push(KeyMap {
            keys,
            modifiers: Some(modifiers.to_string()),
        })
    }

    Keyboard {
        locale: format!("{}-t-k0-{}", name, target),
        names: vec![Names {
            values: vec![Name {
                value: pick_name_from_display_names(&layout.display_names),
            }],
        }],
        key_maps,
        ..Keyboard::default()
    }
}

fn pick_name_from_display_names(names: &BTreeMap<String, String>) -> String {
    names
        .get("en")
        .or_else(|| names.values().next())
        .cloned()
        .unwrap_or_default()
}

#[derive(Snafu, SnafuCliDebug)]
pub enum Error {
    #[snafu(display("Could not load kbdgen bundle"))]
    CannotLoad {
        source: kbdgen::LoadError,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could not write CLDR file"))]
    CannotBeSaved {
        source: SavingError,
        backtrace: snafu::Backtrace,
    },
}

#[derive(Snafu, Debug)]
pub enum SavingError {
    #[snafu(display("Could not create file `{}`", path.display()))]
    CannotCreateFile {
        path: PathBuf,
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
    #[snafu(display("Could transform to xml"))]
    CannotSerializeXml {
        source: std::io::Error,
        backtrace: snafu::Backtrace,
    },
}
<|endoftext|>


<commit_before>use crate::time;
use crate::context;
use crate::syscall::data::TimeSpec;
use crate::syscall::error::*;
use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};

pub fn clock_gettime(clock: usize, time: &mut TimeSpec) -> Result<usize> {
    let arch_time = match clock {
        CLOCK_REALTIME => time::realtime(),
        CLOCK_MONOTONIC => time::monotonic(),
        _ => return Err(Error::new(EINVAL))
    };

    time.tv_sec = arch_time.0 as i64;
    time.tv_nsec = arch_time.1 as i32;
    Ok(0)
}

/// Nanosleep will sleep by switching the current context
pub fn nanosleep(req: &TimeSpec, rem_opt: Option<&mut TimeSpec>) -> Result<usize> {
    //start is a tuple of (seconds, nanoseconds)
    let start = time::monotonic();
    let sum = start.1 + req.tv_nsec as u64;
    let mut end = (start.0 + req.tv_sec as u64 + sum / 1_000_000_000, sum % 1_000_000_000);

    {
        let contexts = context::contexts();
        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
        let mut context = context_lock.write();

        context.wake = Some(end);
        context.block("nanosleep");
    }

    unsafe { context::switch(); }

    if let Some(rem) = rem_opt {
        let current = time::monotonic();

        if current.0 < end.0 || (current.0 == end.0 && current.1 < end.1) {
            if end.1 < current.1 {
                end.0 -= 1;
                end.1 += 1_000_000_000;
            }

            rem.tv_sec = (end.0 - current.0) as i64;
            rem.tv_nsec = (end.1 - current.1) as i32;
        } else {
            rem.tv_sec = 0;
            rem.tv_nsec = 0;
        }
    }

    Ok(0)
}

pub fn sched_yield() -> Result<usize> {
    unsafe { context::switch(); }
    Ok(0)
}
<commit_msg>Work around spurious nanosleep wakes<commit_after>use crate::time;
use crate::context;
use crate::syscall::data::TimeSpec;
use crate::syscall::error::*;
use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};

pub fn clock_gettime(clock: usize, time: &mut TimeSpec) -> Result<usize> {
    let arch_time = match clock {
        CLOCK_REALTIME => time::realtime(),
        CLOCK_MONOTONIC => time::monotonic(),
        _ => return Err(Error::new(EINVAL))
    };

    time.tv_sec = arch_time.0 as i64;
    time.tv_nsec = arch_time.1 as i32;
    Ok(0)
}

/// Nanosleep will sleep by switching the current context
pub fn nanosleep(req: &TimeSpec, rem_opt: Option<&mut TimeSpec>) -> Result<usize> {
    //start is a tuple of (seconds, nanoseconds)
    let start = time::monotonic();
    let sum = start.1 + req.tv_nsec as u64;
    let mut end = (start.0 + req.tv_sec as u64 + sum / 1_000_000_000, sum % 1_000_000_000);

    {
        let contexts = context::contexts();
        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
        let mut context = context_lock.write();

        context.wake = Some(end);
        context.block("nanosleep");
    }

    //TODO: Find out wake reason
    loop {
        unsafe { context::switch(); }

        let contexts = context::contexts();
        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
        let mut context = context_lock.write();
        if context.wake.is_some() {
            context.block("nanosleep spurious");
        } else {
            break;
        }
    }

    if let Some(rem) = rem_opt {
        let current = time::monotonic();

        if current.0 < end.0 || (current.0 == end.0 && current.1 < end.1) {
            if end.1 < current.1 {
                end.0 -= 1;
                end.1 += 1_000_000_000;
            }

            rem.tv_sec = (end.0 - current.0) as i64;
            rem.tv_nsec = (end.1 - current.1) as i32;
        } else {
            rem.tv_sec = 0;
            rem.tv_nsec = 0;
        }
    }

    Ok(0)
}

pub fn sched_yield() -> Result<usize> {
    unsafe { context::switch(); }
    Ok(0)
}
<|endoftext|>