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

<%namespace name="helpers" file="/helpers.mako.rs" />

${helpers.four_sides_shorthand("padding", "padding-%s", "specified::NonNegativeLengthPercentage::parse",
                               spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
                               allow_quirks=True)}
<commit_msg>style: Implement the padding-block/inline shorthands.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

${helpers.four_sides_shorthand("padding", "padding-%s", "specified::NonNegativeLengthPercentage::parse",
                               spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
                               allow_quirks=True)}

% for axis in ["block", "inline"]:
    <%
        spec = "https://drafts.csswg.org/css-logical/#propdef-padding-%s" % axis
    %>
    <%helpers:shorthand
        name="padding-${axis}"
        sub_properties="${' '.join(
            'padding-%s-%s' % (axis, side)
            for side in ['start', 'end']
        )}"
        spec="${spec}">

        use crate::parser::Parse;
        use crate::values::specified::length::NonNegativeLengthPercentage;
        pub fn parse_value<'i, 't>(
            context: &ParserContext,
            input: &mut Parser<'i, 't>,
        ) -> Result<Longhands, ParseError<'i>> {
            let start_value = NonNegativeLengthPercentage::parse(context, input)?;
            let end_value =
                input.try(|input| NonNegativeLengthPercentage::parse(context, input)).unwrap_or_else(|_| start_value.clone());

            Ok(expanded! {
                padding_${axis}_start: start_value,
                padding_${axis}_end: end_value,
            })
        }

        impl<'a> ToCss for LonghandsToSerialize<'a>  {
            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
                self.padding_${axis}_start.to_css(dest)?;

                if self.padding_${axis}_end != self.padding_${axis}_start {
                    dest.write_str(" ")?;
                    self.padding_${axis}_end.to_css(dest)?;
                }

                Ok(())
            }
        }
    </%helpers:shorthand>
% endfor
<|endoftext|>


<commit_before>#![cfg(feature = "stable_graph")]

extern crate petgraph;

use petgraph::graph::stable::StableGraph;

#[test]
fn node_indices() {
    let mut g = StableGraph::<_, ()>::new();
    let a = g.add_node(0);
    let b = g.add_node(1);
    let c = g.add_node(2);
    g.remove_node(b);
    let mut iter = g.node_indices();
    assert_eq!(iter.next(), Some(a));
    assert_eq!(iter.next(), Some(c));
    assert_eq!(iter.next(), None);
}
<commit_msg>stable graph: Test scc with a StableGraph with a hole<commit_after>#![cfg(feature = "stable_graph")]

extern crate petgraph;

use petgraph::graph::stable::StableGraph;
use petgraph::graph::node_index as n;
use petgraph::graph::NodeIndex;
use petgraph::algo::scc;

#[test]
fn node_indices() {
    let mut g = StableGraph::<_, ()>::new();
    let a = g.add_node(0);
    let b = g.add_node(1);
    let c = g.add_node(2);
    g.remove_node(b);
    let mut iter = g.node_indices();
    assert_eq!(iter.next(), Some(a));
    assert_eq!(iter.next(), Some(c));
    assert_eq!(iter.next(), None);
}

fn assert_sccs_eq(mut res: Vec<Vec<NodeIndex>>, normalized: Vec<Vec<NodeIndex>>) {
    // normalize the result and compare with the answer.
    for scc in res.iter_mut() {
        scc.sort();
    }
    // sort by minimum element
    res.sort_by(|v, w| v[0].cmp(&w[0]));
    assert_eq!(res, normalized);
}

#[test]
fn test_scc() {
    let mut gr: StableGraph<(), ()> = StableGraph::from_edges(&[
        (6, 0),
        (0, 3),
        (3, 6),
        (8, 6), (8, 2),
        (2, 5), (5, 8), (7, 5),
        (1, 7),
        (7, 4),
        (4, 1)]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, ());
    gr.add_edge(x, n(1), ());
    gr.remove_node(n(4));

    assert_sccs_eq(scc(&gr), vec![
        vec![n(0), n(3), n(6)],
        vec![n(1), n(7),   x ],
        vec![n(2), n(5), n(8)],
    ]);
}

<|endoftext|>


<commit_before>#[link(name = "glgen",
       author = "Brendan Zabarauskas",
       vers = "0.1")];
#[comment = "OpenGL function loader generator."];

//! Requires libxml2
//!
//! This will be used to generate the loader from the [registry xml files]
//! (https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/):
//!
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml`
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/glx.xml`
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/wgl.xml`

extern mod extra;

use extra::treemap::TreeSet;
use std::io::file_reader;
use std::os;

use registry::Registry;

pub mod registry;

fn main() {
    let args = os::real_args();
    let path_str = args[1].as_slice();

    // Parse the XML registry.
    let reg = Registry::from_xml(
        file_reader(&Path(path_str))
            .expect(fmt!("Could not read %s", path_str))
            .read_c_str()
    );

    // Debug output
    if args.len() > 2 {
        match args[2].as_slice() {
            "--reg" => {
                // Print out the registry data for debugging.
                printfln!("%?", reg);
            }
            "--tys" => {
                // Print out a list of all the types used in the registry.
                print_types(&reg);
            }
            _ => {}
        }
    }

    // TODO: Use registry data to generate function loader.
}

fn gl_ty_conv(ty: &str) -> ~str {
    match ty {
        "GLDEBUGPROC"               => ~"GLDEBUGPROC",
        "GLDEBUGPROCAMD"            => ~"GLDEBUGPROCAMD",
        "GLDEBUGPROCARB"            => ~"GLDEBUGPROCARB",
        "GLDEBUGPROCKHR"            => ~"GLDEBUGPROCKHR",
        "GLbitfield"                => ~"GLbitfield",
        "GLboolean"                 => ~"GLboolean",
        "GLbyte"                    => ~"GLbyte",
        "GLclampd"                  => ~"GLclampd",
        "GLclampf"                  => ~"GLclampf",
        "GLclampx"                  => ~"GLclampx",
        "GLdouble"                  => ~"GLdouble",
        "GLeglImageOES"             => ~"GLeglImageOES",
        "GLenum"                    => ~"GLenum",
        "GLfixed"                   => ~"GLfixed",
        "GLfloat"                   => ~"GLfloat",
        "GLhalfNV"                  => ~"GLhalfNV",
        "GLhandleARB"               => ~"GLhandleARB",
        "GLint"                     => ~"GLint",
        "GLint64EXT"                => ~"GLint64EXT",
        "GLintptr"                  => ~"GLintptr",
        "GLintptrARB"               => ~"GLintptrARB",
        "GLshort"                   => ~"GLshort",
        "GLsizei"                   => ~"GLsizei",
        "GLsizeiptr"                => ~"GLsizeiptr",
        "GLsizeiptrARB"             => ~"GLsizeiptrARB",
        "GLsync"                    => ~"GLsync",
        "GLubyte"                   => ~"GLubyte",
        "GLuint"                    => ~"GLuint",
        "GLuint64"                  => ~"GLuint64",
        "GLuint64EXT"               => ~"GLuint64EXT",
        "GLushort"                  => ~"GLushort",
        "GLvdpauSurfaceNV"          => ~"GLvdpauSurfaceNV",
        "GLboolean *"               => ~"*GLboolean",
        "GLchar *"                  => ~"*GLchar",
        "GLcharARB *"               => ~"*GLcharARB",
        "GLdouble *"                => ~"*GLdouble",
        "GLenum *"                  => ~"*GLenum",
        "GLfixed *"                 => ~"*GLfixed",
        "GLfloat *"                 => ~"*GLfloat",
        "GLhandleARB *"             => ~"*GLhandleARB",
        "GLint *"                   => ~"*GLint",
        "GLint64 *"                 => ~"*GLint64",
        "GLint64EXT *"              => ~"*GLint64EXT",
        "GLsizei *"                 => ~"*GLsizei",
        "GLubyte *"                 => ~"*GLubyte",
        "GLuint *"                  => ~"*GLuint",
        "GLuint64 *"                => ~"*GLuint64",
        "GLuint64EXT *"             => ~"*GLuint64EXT",
        "GLushort *"                => ~"*GLushort",
        "GLvoid *"                  => ~"*GLvoid",
        "GLvoid **"                 => ~"**GLvoid",
        "const GLboolean *"         => ~"*GLboolean",
        "const GLbyte *"            => ~"*GLbyte",
        "const GLchar *"            => ~"*GLchar",
        "const GLcharARB *"         => ~"*GLcharARB",
        "const GLclampf *"          => ~"*GLclampf",
        "const GLdouble *"          => ~"*GLdouble",
        "const GLenum *"            => ~"*GLenum",
        "const GLfixed *"           => ~"*GLfixed",
        "const GLfloat *"           => ~"*GLfloat",
        "const GLhalfNV *"          => ~"*GLhalfNV",
        "const GLint *"             => ~"*GLint",
        "const GLint64EXT *"        => ~"*GLint64EXT",
        "const GLintptr *"          => ~"*GLintptr",
        "const GLshort *"           => ~"*GLshort",
        "const GLsizei *"           => ~"*GLsizei",
        "const GLsizeiptr *"        => ~"*GLsizeiptr",
        "const GLubyte *"           => ~"*GLubyte",
        "const GLuint *"            => ~"*GLuint",
        "const GLuint64 *"          => ~"*GLuint64",
        "const GLuint64EXT *"       => ~"*GLuint64EXT",
        "const GLushort *"          => ~"*GLushort",
        "const GLvdpauSurfaceNV *"  => ~"*GLvdpauSurfaceNV",
        "const GLvoid *"            => ~"*GLvoid",
        "const void *"              => ~"*c_void",
        "const GLboolean **"        => ~"**GLboolean",
        "const GLchar **"           => ~"**GLchar",
        "const GLcharARB **"        => ~"**GLcharARB",
        "const GLvoid **"           => ~"**GLvoid",
        "const GLchar *const*"      => ~"**GLchar",
        "const GLvoid *const*"      => ~"**GLvoid",
        "struct _cl_context *"      => ~"*_cl_context",
        "struct _cl_event *"        => ~"*_cl_event",
        "void "                     => ~"c_void",
        "void *"                    => ~"*c_void",
        _                           => fail!("Type conversion not yet implemented for `%s`", ty),
    }
}

fn print_types(reg: &Registry) {
    let mut tys = TreeSet::new();
    for cmds in reg.cmds.iter() {
        for def in cmds.defs.iter() {
            tys.insert(&def.proto.ty);
            for param in def.params.iter() {
                tys.insert(&param.ty);
            }
        }
    }
    for ty in tys.iter() {
        printfln!("        \"%s\"", **ty);
    }
}
<commit_msg>Implement type conversions for glx and wgl types<commit_after>#[link(name = "glgen",
       author = "Brendan Zabarauskas",
       vers = "0.1")];
#[comment = "OpenGL function loader generator."];

//! Requires libxml2
//!
//! This will be used to generate the loader from the [registry xml files]
//! (https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/):
//!
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml`
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/glx.xml`
//! - `$ wget --no-check-certificate https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/wgl.xml`

extern mod extra;

use extra::treemap::TreeSet;
use std::io::file_reader;
use std::os;

use registry::Registry;

pub mod registry;

fn main() {
    let args = os::real_args();
    let path_str = args[1].as_slice();

    // Parse the XML registry.
    let reg = Registry::from_xml(
        file_reader(&Path(path_str))
            .expect(fmt!("Could not read %s", path_str))
            .read_c_str()
    );

    // Debug output
    if args.len() > 2 {
        match args[2].as_slice() {
            "--reg" => {
                // Print out the registry data for debugging.
                printfln!("%?", reg);
            }
            "--ctys" => {
                // Print out a list of all the types used in the registry.
                let tys = get_tys(&reg);
                for ty in tys.iter() {
                    printfln!("\"%s\"", *ty);
                }
            }
            "--rtys" => {
                // Print out a list of all the types used in the registry,
                // converted to rust syntax.
                let tys = get_tys(&reg);
                for ty in tys.iter() {
                    printfln!("\"%s\"", cty_conv(*ty));
                }
            }
            _ => {}
        }
    }

    // TODO: Use registry data to generate function loader.
}

fn cty_conv(ty: &str) -> ~str {
    match ty {
        // gl.xml types
        "GLDEBUGPROC"               => ~"GLDEBUGPROC",
        "GLDEBUGPROCAMD"            => ~"GLDEBUGPROCAMD",
        "GLDEBUGPROCARB"            => ~"GLDEBUGPROCARB",
        "GLDEBUGPROCKHR"            => ~"GLDEBUGPROCKHR",
        "GLbitfield"                => ~"GLbitfield",
        "GLboolean"                 => ~"GLboolean",
        "GLbyte"                    => ~"GLbyte",
        "GLclampd"                  => ~"GLclampd",
        "GLclampf"                  => ~"GLclampf",
        "GLclampx"                  => ~"GLclampx",
        "GLdouble"                  => ~"GLdouble",
        "GLeglImageOES"             => ~"GLeglImageOES",
        "GLenum"                    => ~"GLenum",
        "GLfixed"                   => ~"GLfixed",
        "GLfloat"                   => ~"GLfloat",
        "GLhalfNV"                  => ~"GLhalfNV",
        "GLhandleARB"               => ~"GLhandleARB",
        "GLint"                     => ~"GLint",
        "GLint64EXT"                => ~"GLint64EXT",
        "GLintptr"                  => ~"GLintptr",
        "GLintptrARB"               => ~"GLintptrARB",
        "GLshort"                   => ~"GLshort",
        "GLsizei"                   => ~"GLsizei",
        "GLsizeiptr"                => ~"GLsizeiptr",
        "GLsizeiptrARB"             => ~"GLsizeiptrARB",
        "GLsync"                    => ~"GLsync",
        "GLubyte"                   => ~"GLubyte",
        "GLuint"                    => ~"GLuint",
        "GLuint64"                  => ~"GLuint64",
        "GLuint64EXT"               => ~"GLuint64EXT",
        "GLushort"                  => ~"GLushort",
        "GLvdpauSurfaceNV"          => ~"GLvdpauSurfaceNV",
        "void "                     => ~"c_void",
        "GLboolean *"               => ~"*GLboolean",
        "GLchar *"                  => ~"*GLchar",
        "GLcharARB *"               => ~"*GLcharARB",
        "GLdouble *"                => ~"*GLdouble",
        "GLenum *"                  => ~"*GLenum",
        "GLfixed *"                 => ~"*GLfixed",
        "GLfloat *"                 => ~"*GLfloat",
        "GLhandleARB *"             => ~"*GLhandleARB",
        "GLint *"                   => ~"*GLint",
        "GLint64 *"                 => ~"*GLint64",
        "GLint64EXT *"              => ~"*GLint64EXT",
        "GLsizei *"                 => ~"*GLsizei",
        "GLubyte *"                 => ~"*GLubyte",
        "GLuint *"                  => ~"*GLuint",
        "GLuint64 *"                => ~"*GLuint64",
        "GLuint64EXT *"             => ~"*GLuint64EXT",
        "GLushort *"                => ~"*GLushort",
        "GLvoid *"                  => ~"*GLvoid",
        "GLvoid **"                 => ~"**GLvoid",
        "const GLboolean *"         => ~"*GLboolean",
        "const GLbyte *"            => ~"*GLbyte",
        "const GLchar *"            => ~"*GLchar",
        "const GLcharARB *"         => ~"*GLcharARB",
        "const GLclampf *"          => ~"*GLclampf",
        "const GLdouble *"          => ~"*GLdouble",
        "const GLenum *"            => ~"*GLenum",
        "const GLfixed *"           => ~"*GLfixed",
        "const GLfloat *"           => ~"*GLfloat",
        "const GLhalfNV *"          => ~"*GLhalfNV",
        "const GLint *"             => ~"*GLint",
        "const GLint64EXT *"        => ~"*GLint64EXT",
        "const GLintptr *"          => ~"*GLintptr",
        "const GLshort *"           => ~"*GLshort",
        "const GLsizei *"           => ~"*GLsizei",
        "const GLsizeiptr *"        => ~"*GLsizeiptr",
        "const GLubyte *"           => ~"*GLubyte",
        "const GLuint *"            => ~"*GLuint",
        "const GLuint64 *"          => ~"*GLuint64",
        "const GLuint64EXT *"       => ~"*GLuint64EXT",
        "const GLushort *"          => ~"*GLushort",
        "const GLvdpauSurfaceNV *"  => ~"*GLvdpauSurfaceNV",
        "const GLvoid *"            => ~"*GLvoid",
        "const void *"              => ~"*c_void",
        "void *"                    => ~"*c_void",
        "const GLboolean **"        => ~"**GLboolean",
        "const GLchar **"           => ~"**GLchar",
        "const GLcharARB **"        => ~"**GLcharARB",
        "const GLvoid **"           => ~"**GLvoid",
        "const GLchar *const*"      => ~"**GLchar",
        "const GLvoid *const*"      => ~"**GLvoid",
        "struct _cl_context *"      => ~"*_cl_context",
        "struct _cl_event *"        => ~"*_cl_event",

        // glx.xml types
        "Bool"                      => ~"Bool",
        "Colormap"                  => ~"Colormap",
        "DMbuffer"                  => ~"DMbuffer",
        "Font"                      => ~"Font",
        "GLXContext"                => ~"GLXContext",
        "GLXContextID"              => ~"GLXContextID",
        "GLXDrawable"               => ~"GLXDrawable",
        "GLXFBConfig"               => ~"GLXFBConfig",
        "GLXFBConfigSGIX"           => ~"GLXFBConfigSGIX",
        "GLXPbuffer"                => ~"GLXPbuffer",
        "GLXPbufferSGIX"            => ~"GLXPbufferSGIX",
        "GLXPixmap"                 => ~"GLXPixmap",
        "GLXVideoCaptureDeviceNV"   => ~"GLXVideoCaptureDeviceNV",
        "GLXVideoDeviceNV"          => ~"GLXVideoDeviceNV",
        "GLXVideoSourceSGIX"        => ~"GLXVideoSourceSGIX",
        "GLXWindow"                 => ~"GLXWindow",
        // "GLboolean"                 => ~"GLboolean",
        // "GLenum"                    => ~"GLenum",
        // "GLint"                     => ~"GLint",
        // "GLsizei"                   => ~"GLsizei",
        // "GLuint"                    => ~"GLuint",
        "Pixmap"                    => ~"Pixmap",
        "Status"                    => ~"Status",
        "VLNode"                    => ~"VLNode",
        "VLPath"                    => ~"VLPath",
        "VLServer"                  => ~"VLServer",
        "Window"                    => ~"Window",
        "__GLXextFuncPtr"           => ~"__GLXextFuncPtr",
        "const GLXContext"          => ~"const GLXContext",
        "float "                    => ~"c_float",
        "int "                      => ~"c_int",
        "int64_t"                   => ~"i64",
        "unsigned int "             => ~"c_uint",
        "unsigned long "            => ~"c_ulong",
        // "void "                     => ~"c_void",
        "DMparams *"                => ~"*DMparams",
        "Display *"                 => ~"*Display",
        "GLXFBConfig *"             => ~"*GLXFBConfig",
        "GLXFBConfigSGIX *"         => ~"*GLXFBConfigSGIX",
        "GLXHyperpipeConfigSGIX *"  => ~"*GLXHyperpipeConfigSGIX",
        "GLXHyperpipeNetworkSGIX *" => ~"*GLXHyperpipeNetworkSGIX",
        "GLXVideoCaptureDeviceNV *" => ~"*GLXVideoCaptureDeviceNV",
        "GLXVideoDeviceNV *"        => ~"*GLXVideoDeviceNV",
        // "GLuint *"                  => ~"*GLuint",
        "XVisualInfo *"             => ~"*XVisualInfo",
        // "const GLubyte *"           => ~"*GLubyte",
        "const char *"              => ~"*c_char",
        "const int *"               => ~"*c_int",
        // "const void *"              => ~"*c_void",
        "int *"                     => ~"*c_int",
        "int32_t *"                 => ~"*i32",
        "int64_t *"                 => ~"*i64",
        "long *"                    => ~"*c_long",
        "unsigned int *"            => ~"*c_uint",
        "unsigned long *"           => ~"*c_ulong",
        // "void *"                    => ~"*c_void",

        // wgl.xml types
        "BOOL"                      => ~"BOOL",
        "DWORD"                     => ~"DWORD",
        "FLOAT"                     => ~"FLOAT",
        // "GLbitfield"                => ~"GLbitfield",
        // "GLboolean"                 => ~"GLboolean",
        // "GLenum"                    => ~"GLenum",
        // "GLfloat"                   => ~"GLfloat",
        // "GLint"                     => ~"GLint",
        // "GLsizei"                   => ~"GLsizei",
        // "GLuint"                    => ~"GLuint",
        // "GLushort"                  => ~"GLushort",
        "HANDLE"                    => ~"HANDLE",
        "HDC"                       => ~"HDC",
        "HENHMETAFILE"              => ~"HENHMETAFILE",
        "HGLRC"                     => ~"HGLRC",
        "HGPUNV"                    => ~"HGPUNV",
        "HPBUFFERARB"               => ~"HPBUFFERARB",
        "HPBUFFEREXT"               => ~"HPBUFFEREXT",
        "HPVIDEODEV"                => ~"HPVIDEODEV",
        "HVIDEOINPUTDEVICENV"       => ~"HVIDEOINPUTDEVICENV",
        "HVIDEOOUTPUTDEVICENV"      => ~"HVIDEOOUTPUTDEVICENV",
        "INT"                       => ~"INT",
        "INT64"                     => ~"INT64",
        "LPCSTR"                    => ~"LPCSTR",
        "LPGLYPHMETRICSFLOAT"       => ~"LPGLYPHMETRICSFLOAT",
        "LPVOID"                    => ~"LPVOID",
        "PGPU_DEVICE"               => ~"PGPU_DEVICE",
        "PROC"                      => ~"PROC",
        "UINT"                      => ~"UINT",
        "VOID"                      => ~"VOID",
        // "int "                      => ~"c_int",
        // "unsigned int "             => ~"c_uint",
        // "void "                     => ~"c_void",
        "BOOL *"                    => ~"*BOOL",
        "DWORD *"                   => ~"*DWORD",
        "FLOAT *"                   => ~"*FLOAT",
        // "GLuint *"                  => ~"*GLuint",
        "HANDLE *"                  => ~"*HANDLE",
        "HGPUNV *"                  => ~"*HGPUNV",
        "HPVIDEODEV *"              => ~"*HPVIDEODEV",
        "HVIDEOINPUTDEVICENV *"     => ~"*HVIDEOINPUTDEVICENV",
        "HVIDEOOUTPUTDEVICENV *"    => ~"*HVIDEOOUTPUTDEVICENV",
        "INT32 *"                   => ~"*INT32",
        "INT64 *"                   => ~"*INT64",
        "UINT *"                    => ~"*UINT",
        "USHORT *"                  => ~"*USHORT",
        "const COLORREF *"          => ~"*COLORREF",
        "const DWORD *"             => ~"*DWORD",
        "const FLOAT *"             => ~"*FLOAT",
        // "const GLushort *"          => ~"*GLushort",
        "const HANDLE *"            => ~"*HANDLE",
        "const HGPUNV *"            => ~"*HGPUNV",
        "const LAYERPLANEDESCRIPTOR *"  => ~"*LAYERPLANEDESCRIPTOR",
        "const LPVOID *"            => ~"*LPVOID",
        "const PIXELFORMATDESCRIPTOR *" => ~"*PIXELFORMATDESCRIPTOR",
        "const USHORT *"            => ~"*USHORT",
        // "const char *"              => ~"*c_char",
        // "const int *"               => ~"*c_int",
        "float *"                   => ~"*c_float",
        // "int *"                     => ~"*c_int",
        // "unsigned long *"           => ~"*c_ulong",
        // "void *"                    => ~"*c_void",

        // failure
        _ => fail!("Type conversion not implemented for `%s`", ty),
    }
}

fn get_tys(reg: &Registry) -> TreeSet<~str> {
    let mut tys = TreeSet::new();
    for cmds in reg.cmds.iter() {
        for def in cmds.defs.iter() {
            tys.insert(def.proto.ty.clone());
            for param in def.params.iter() {
                tys.insert(param.ty.clone());
            }
        }
    }
    tys
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {

    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

#[test]
fn different_request_count() {
    unimplemented!();
}

//TODO: Find a sensible way of testing timeout lengths

#[test]
fn empty_polling() {
    unimplemented!();
}

#[test]
fn single_item_polling() {
    unimplemented!();
}

#[test]
fn multiple_item_polling() {
    unimplemented!();
}

#[test]
fn disconnection() {
    unimplemented!();
}

#[test]
fn timeout() {
    unimplemented!();
}

#[test]
fn send_correct_handshake() {
    unimplemented!();
}

#[test]
fn send_data() {
    unimplemented!();
}
<commit_msg>All connection-creating requests tested for Client<commit_after>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {

    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * We should be able to specify how many retries we want
 */
#[test]
fn different_retry_count() {
    let port = 65004;
    let (my_addr, target_addr, settings, mut client_settings) = generate_settings(port, 121);
    client_settings.max_connect_retries = 3;

    let (tx, rx) = channel();
    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let mut attempts = 0u8;
        while attempts < 3 {
            get_message(&mut socket);
            attempts += 1;
        }

        tx.send(attempts);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => (),
        Err(e) => ()
    };

    assert!(rx.recv() == 3);
}

//TODO: Find a sensible way of testing timeout lengths

#[test]
fn empty_polling() {
    unimplemented!();
}

#[test]
fn single_item_polling() {
    unimplemented!();
}

#[test]
fn multiple_item_polling() {
    unimplemented!();
}

#[test]
fn disconnection() {
    unimplemented!();
}

#[test]
fn timeout() {
    unimplemented!();
}

#[test]
fn send_correct_handshake() {
    unimplemented!();
}

#[test]
fn send_data() {
    unimplemented!();
}
<|endoftext|>


<commit_before>use neb::server::*;
use neb::ram::schema::*;
use neb::server::transactions;
use neb::ram::types::*;
use neb::server::transactions::*;
use std::rc::Rc;
use neb::ram::cell::*;
use super::*;

#[test]
pub fn workspace_wr() {
    let server_addr = String::from("127.0.0.1:5200");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("write cell 1 not accepted {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    data_map.insert(String::from("score"), Value::U64(90));
    let cell_1_w2 = Cell::new(schema.id, &cell_1.id(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {panic!("Write existed cell should fail")}
        TxnExecResult::Error(WriteError::CellAlreadyExisted) => {}
        _ => {panic!("Wrong feedback {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    let cell_1_u_res = txn.update(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_u_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("update cell 1 not accepted")}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 90);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    let cell_1_rm_res = txn.remove(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_rm_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("remove cell 1 not accepted {:?}", cell_1_rm_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Error(ReadError::CellDoesNotExisted) => {},
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    assert_eq!(txn.prepare(&txn_id).unwrap().unwrap(), TMPrepareResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap().unwrap(), EndResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap(), Err(TMError::TransactionNotFound));
    // committed transaction should have been disposed
}

#[test]
pub fn data_site_wr() {
    let server_addr = String::from("127.0.0.1:5201");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    let cell_1_non_exists_read = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_non_exists_read {
        TxnExecResult::Error(ReadError::CellDoesNotExisted) => {},
        _ => {panic!("read non-existed cell should fail but got {:?}", cell_1_non_exists_read)}
    }
    let cell_1_write = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    data_map.insert(String::from("score"), Value::U64(90));
    let cell_1_w2 = Cell::new(schema.id, &cell_1.id(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {panic!("Write existed cell should fail")}
        TxnExecResult::Error(WriteError::CellAlreadyExisted) => {}
        _ => {panic!("Wrong feedback {:?}", cell_1_w_res)}
    }
    assert_eq!(txn.prepare(&txn_id).unwrap().unwrap(), TMPrepareResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap().unwrap(), EndResult::Success);

}<commit_msg>transaction write test<commit_after>use neb::server::*;
use neb::ram::schema::*;
use neb::server::transactions;
use neb::ram::types::*;
use neb::server::transactions::*;
use std::rc::Rc;
use neb::ram::cell::*;
use super::*;

#[test]
pub fn workspace_wr() {
    let server_addr = String::from("127.0.0.1:5200");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("write cell 1 not accepted {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    data_map.insert(String::from("score"), Value::U64(90));
    let cell_1_w2 = Cell::new(schema.id, &cell_1.id(), data_map.clone());
    let cell_1_w_res = txn.write(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {panic!("Write existed cell should fail")}
        TxnExecResult::Error(WriteError::CellAlreadyExisted) => {}
        _ => {panic!("Wrong feedback {:?}", cell_1_w_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    let cell_1_u_res = txn.update(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_u_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("update cell 1 not accepted")}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 90);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    let cell_1_rm_res = txn.remove(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_rm_res {
        TxnExecResult::Accepted(()) => {},
        _ => {panic!("remove cell 1 not accepted {:?}", cell_1_rm_res)}
    }
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Error(ReadError::CellDoesNotExisted) => {},
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    assert_eq!(txn.prepare(&txn_id).unwrap().unwrap(), TMPrepareResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap().unwrap(), EndResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap(), Err(TMError::TransactionNotFound));
    // committed transaction should have been disposed
}

#[test]
pub fn data_site_wr() {
    let server_addr = String::from("127.0.0.1:5201");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    server.meta.schemas.new_schema(&mut schema);
    let txn = transactions::new_client(&server_addr).unwrap();
    let txn_id = txn.begin().unwrap().unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    let cell_1_non_exists_read = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_non_exists_read {
        TxnExecResult::Error(ReadError::CellDoesNotExisted) => {},
        _ => {panic!("read non-existed cell should fail but got {:?}", cell_1_non_exists_read)}
    }
    let cell_1_write = txn.write(&txn_id, &cell_1).unwrap().unwrap();
    let cell_1_r_res = txn.read(&txn_id, &cell_1.id()).unwrap().unwrap();
    match cell_1_r_res {
        TxnExecResult::Accepted(cell) => {
            assert_eq!(cell.id(), cell_1.id());
            assert_eq!(cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
            assert_eq!(cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
            assert_eq!(cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
        },
        _ => {panic!("read cell 1 not accepted {:?}", cell_1_r_res)}
    }
    data_map.insert(String::from("score"), Value::U64(90));
    let cell_1_w2 = Cell::new(schema.id, &cell_1.id(), data_map.clone());
    let cell_1_w_res = txn.update(&txn_id, &cell_1_w2).unwrap().unwrap();
    match cell_1_w_res {
        TxnExecResult::Accepted(()) => {}
        _ => {panic!("Wrong feedback {:?}", cell_1_w_res)}
    }
    assert_eq!(txn.prepare(&txn_id).unwrap().unwrap(), TMPrepareResult::Success);
    assert_eq!(txn.commit(&txn_id).unwrap().unwrap(), EndResult::Success);
    let cell_r2 = server.chunks.read_cell(&cell_1.id()).unwrap();
    assert_eq!(cell_r2.id(), cell_1.id());
    assert_eq!(cell_r2.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
    assert_eq!(cell_r2.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
    assert_eq!(cell_r2.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 90);
}<|endoftext|>


<commit_before>use crate::os::unix::prelude::*;

use crate::ffi::{OsString, OsStr, CString, CStr};
use crate::fmt;
use crate::io;
use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::collections::BTreeMap;

use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

pub struct Command {
    // Currently we try hard to ensure that the call to `.exec()` doesn't
    // actually allocate any memory. While many platforms try to ensure that
    // memory allocation works after a fork in a multithreaded process, it's
    // been observed to be buggy and somewhat unreliable, so we do our best to
    // just not do it at all!
    //
    // Along those lines, the `argv` and `envp` raw pointers here are exactly
    // what's gonna get passed to `execvp`. The `argv` array starts with the
    // `program` and ends with a NULL, and the `envp` pointer, if present, is
    // also null-terminated.
    //
    // Right now we don't support removing arguments, so there's no much fancy
    // support there, but we support adding and removing environment variables,
    // so a side table is used to track where in the `envp` array each key is
    // located. Whenever we add a key we update it in place if it's already
    // present, and whenever we remove a key we update the locations of all
    // other keys.
    program: CString,
    args: Vec<CString>,
    argv: Argv,
    env: CommandEnv<DefaultEnvKey>,

    cwd: Option<CString>,
    uid: Option<uid_t>,
    gid: Option<gid_t>,
    saw_nul: bool,
    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
    stdin: Option<Stdio>,
    stdout: Option<Stdio>,
    stderr: Option<Stdio>,
}

// Create a new type for argv, so that we can make it `Send`
struct Argv(Vec<*const c_char>);

// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
unsafe impl Send for Argv {}

// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
    pub stdin: Option<AnonPipe>,
    pub stdout: Option<AnonPipe>,
    pub stderr: Option<AnonPipe>,
}

// passed to do_exec() with configuration of what the child stdio should look
// like
pub struct ChildPipes {
    pub stdin: ChildStdio,
    pub stdout: ChildStdio,
    pub stderr: ChildStdio,
}

pub enum ChildStdio {
    Inherit,
    Explicit(c_int),
    Owned(FileDesc),
}

pub enum Stdio {
    Inherit,
    Null,
    MakePipe,
    Fd(FileDesc),
}

impl Command {
    pub fn new(program: &OsStr) -> Command {
        let mut saw_nul = false;
        let program = os2c(program, &mut saw_nul);
        Command {
            argv: Argv(vec![program.as_ptr(), ptr::null()]),
            program,
            args: Vec::new(),
            env: Default::default(),
            cwd: None,
            uid: None,
            gid: None,
            saw_nul,
            closures: Vec::new(),
            stdin: None,
            stdout: None,
            stderr: None,
        }
    }

    pub fn arg(&mut self, arg: &OsStr) {
        // Overwrite the trailing NULL pointer in `argv` and then add a new null
        // pointer.
        let arg = os2c(arg, &mut self.saw_nul);
        self.argv.0[self.args.len() + 1] = arg.as_ptr();
        self.argv.0.push(ptr::null());

        // Also make sure we keep track of the owned value to schedule a
        // destructor for this memory.
        self.args.push(arg);
    }

    pub fn cwd(&mut self, dir: &OsStr) {
        self.cwd = Some(os2c(dir, &mut self.saw_nul));
    }
    pub fn uid(&mut self, id: uid_t) {
        self.uid = Some(id);
    }
    pub fn gid(&mut self, id: gid_t) {
        self.gid = Some(id);
    }

    pub fn saw_nul(&self) -> bool {
        self.saw_nul
    }
    pub fn get_argv(&self) -> &Vec<*const c_char> {
        &self.argv.0
    }

    #[allow(dead_code)]
    pub fn get_cwd(&self) -> &Option<CString> {
        &self.cwd
    }
    #[allow(dead_code)]
    pub fn get_uid(&self) -> Option<uid_t> {
        self.uid
    }
    #[allow(dead_code)]
    pub fn get_gid(&self) -> Option<gid_t> {
        self.gid
    }

    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
        &mut self.closures
    }

    pub unsafe fn pre_exec(
        &mut self,
        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
    ) {
        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
        unimplemented!();;
    }

    pub fn stdin(&mut self, stdin: Stdio) {
        self.stdin = Some(stdin);
    }

    pub fn stdout(&mut self, stdout: Stdio) {
        self.stdout = Some(stdout);
    }

    pub fn stderr(&mut self, stderr: Stdio) {
        self.stderr = Some(stderr);
    }

    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
        &mut self.env
    }

    pub fn capture_env(&mut self) -> Option<CStringArray> {
        let maybe_env = self.env.capture_if_changed();
        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
    }
    #[allow(dead_code)]
    pub fn env_saw_path(&self) -> bool {
        self.env.have_changed_path()
    }

    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
                -> io::Result<(StdioPipes, ChildPipes)> {
        let null = Stdio::Null;
        let default_stdin = if needs_stdin {&default} else {&null};
        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
        let stdout = self.stdout.as_ref().unwrap_or(&default);
        let stderr = self.stderr.as_ref().unwrap_or(&default);
        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
        let ours = StdioPipes {
            stdin: our_stdin,
            stdout: our_stdout,
            stderr: our_stderr,
        };
        let theirs = ChildPipes {
            stdin: their_stdin,
            stdout: their_stdout,
            stderr: their_stderr,
        };
        Ok((ours, theirs))
    }
}

fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
        *saw_nul = true;
        CString::new("<string-with-nul>").unwrap()
    })
}

// Helper type to manage ownership of the strings within a C-style array.
pub struct CStringArray {
    items: Vec<CString>,
    ptrs: Vec<*const c_char>
}

impl CStringArray {
    pub fn with_capacity(capacity: usize) -> Self {
        let mut result = CStringArray {
            items: Vec::with_capacity(capacity),
            ptrs: Vec::with_capacity(capacity+1)
        };
        result.ptrs.push(ptr::null());
        result
    }
    pub fn push(&mut self, item: CString) {
        let l = self.ptrs.len();
        self.ptrs[l-1] = item.as_ptr();
        self.ptrs.push(ptr::null());
        self.items.push(item);
    }
    pub fn as_ptr(&self) -> *const *const c_char {
        self.ptrs.as_ptr()
    }
}

fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
    let mut result = CStringArray::with_capacity(env.len());
    for (k, v) in env {
        let mut k: OsString = k.into();

        // Reserve additional space for '=' and null terminator
        k.reserve_exact(v.len() + 2);
        k.push("=");
        k.push(&v);

        // Add the new entry into the array
        if let Ok(item) = CString::new(k.into_vec()) {
            result.push(item);
        } else {
            *saw_nul = true;
        }
    }

    result
}

impl Stdio {
    pub fn to_child_stdio(&self, readable: bool)
                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
        match *self {
            Stdio::Inherit => {
                Ok((ChildStdio::Inherit, None))
            },

            // Make sure that the source descriptors are not an stdio
            // descriptor, otherwise the order which we set the child's
            // descriptors may blow away a descriptor which we are hoping to
            // save. For example, suppose we want the child's stderr to be the
            // parent's stdout, and the child's stdout to be the parent's
            // stderr. No matter which we dup first, the second will get
            // overwritten prematurely.
            Stdio::Fd(ref fd) => {
                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
                } else {
                    Ok((ChildStdio::Explicit(fd.raw()), None))
                }
            }

            Stdio::MakePipe => {
                let (reader, writer) = pipe::anon_pipe()?;
                let (ours, theirs) = if readable {
                    (writer, reader)
                } else {
                    (reader, writer)
                };
                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
            }

            Stdio::Null => {
                let mut opts = OpenOptions::new();
                opts.read(readable);
                opts.write(!readable);
                let path = unsafe {
                    CStr::from_ptr("/null\0".as_ptr() as *const _)
                };
                let fd = File::open_c(&path, &opts)?;
                Ok((ChildStdio::Owned(fd.into_fd()), None))
            }
        }
    }
}

impl From<AnonPipe> for Stdio {
    fn from(pipe: AnonPipe) -> Stdio {
        Stdio::Fd(pipe.into_fd())
    }
}

impl From<File> for Stdio {
    fn from(file: File) -> Stdio {
        Stdio::Fd(file.into_fd())
    }
}

impl ChildStdio {
    pub fn fd(&self) -> Option<c_int> {
        match *self {
            ChildStdio::Inherit => None,
            ChildStdio::Explicit(fd) => Some(fd),
            ChildStdio::Owned(ref fd) => Some(fd.raw()),
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)?;
        for arg in &self.args {
            write!(f, " {:?}", arg)?;
        }
        Ok(())
    }
}

/// Unix exit statuses
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(c_int);

impl ExitStatus {
    pub fn new(status: c_int) -> ExitStatus {
        ExitStatus(status)
    }

    fn exited(&self) -> bool {
        /*unsafe*/ { libc::WIFEXITED(self.0) }
    }

    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        if self.exited() {
            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
        } else {
            None
        }
    }

    pub fn signal(&self) -> Option<i32> {
        if !self.exited() {
            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
        } else {
            None
        }
    }
}

impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(code) = self.code() {
            write!(f, "exit code: {}", code)
        } else {
            let signal = self.signal().unwrap();
            write!(f, "signal: {}", signal)
        }
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(u8);

impl ExitCode {
    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);

    #[inline]
    pub fn as_i32(&self) -> i32 {
        self.0 as i32
    }
}
<commit_msg>Rollup merge of #63704 - Wind-River:master, r=Centril<commit_after>use crate::os::unix::prelude::*;

use crate::ffi::{OsString, OsStr, CString, CStr};
use crate::fmt;
use crate::io;
use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use crate::collections::BTreeMap;

use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

pub struct Command {
    // Currently we try hard to ensure that the call to `.exec()` doesn't
    // actually allocate any memory. While many platforms try to ensure that
    // memory allocation works after a fork in a multithreaded process, it's
    // been observed to be buggy and somewhat unreliable, so we do our best to
    // just not do it at all!
    //
    // Along those lines, the `argv` and `envp` raw pointers here are exactly
    // what's gonna get passed to `execvp`. The `argv` array starts with the
    // `program` and ends with a NULL, and the `envp` pointer, if present, is
    // also null-terminated.
    //
    // Right now we don't support removing arguments, so there's no much fancy
    // support there, but we support adding and removing environment variables,
    // so a side table is used to track where in the `envp` array each key is
    // located. Whenever we add a key we update it in place if it's already
    // present, and whenever we remove a key we update the locations of all
    // other keys.
    program: CString,
    args: Vec<CString>,
    argv: Argv,
    env: CommandEnv<DefaultEnvKey>,

    cwd: Option<CString>,
    uid: Option<uid_t>,
    gid: Option<gid_t>,
    saw_nul: bool,
    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
    stdin: Option<Stdio>,
    stdout: Option<Stdio>,
    stderr: Option<Stdio>,
}

// Create a new type for argv, so that we can make it `Send`
struct Argv(Vec<*const c_char>);

// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
unsafe impl Send for Argv {}

// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
    pub stdin: Option<AnonPipe>,
    pub stdout: Option<AnonPipe>,
    pub stderr: Option<AnonPipe>,
}

// passed to do_exec() with configuration of what the child stdio should look
// like
pub struct ChildPipes {
    pub stdin: ChildStdio,
    pub stdout: ChildStdio,
    pub stderr: ChildStdio,
}

pub enum ChildStdio {
    Inherit,
    Explicit(c_int),
    Owned(FileDesc),
}

pub enum Stdio {
    Inherit,
    Null,
    MakePipe,
    Fd(FileDesc),
}

impl Command {
    pub fn new(program: &OsStr) -> Command {
        let mut saw_nul = false;
        let program = os2c(program, &mut saw_nul);
        Command {
            argv: Argv(vec![program.as_ptr(), ptr::null()]),
            program,
            args: Vec::new(),
            env: Default::default(),
            cwd: None,
            uid: None,
            gid: None,
            saw_nul,
            closures: Vec::new(),
            stdin: None,
            stdout: None,
            stderr: None,
        }
    }

    pub fn arg(&mut self, arg: &OsStr) {
        // Overwrite the trailing NULL pointer in `argv` and then add a new null
        // pointer.
        let arg = os2c(arg, &mut self.saw_nul);
        self.argv.0[self.args.len() + 1] = arg.as_ptr();
        self.argv.0.push(ptr::null());

        // Also make sure we keep track of the owned value to schedule a
        // destructor for this memory.
        self.args.push(arg);
    }

    pub fn cwd(&mut self, dir: &OsStr) {
        self.cwd = Some(os2c(dir, &mut self.saw_nul));
    }
    pub fn uid(&mut self, id: uid_t) {
        self.uid = Some(id);
    }
    pub fn gid(&mut self, id: gid_t) {
        self.gid = Some(id);
    }

    pub fn saw_nul(&self) -> bool {
        self.saw_nul
    }
    pub fn get_argv(&self) -> &Vec<*const c_char> {
        &self.argv.0
    }

    #[allow(dead_code)]
    pub fn get_cwd(&self) -> &Option<CString> {
        &self.cwd
    }
    #[allow(dead_code)]
    pub fn get_uid(&self) -> Option<uid_t> {
        self.uid
    }
    #[allow(dead_code)]
    pub fn get_gid(&self) -> Option<gid_t> {
        self.gid
    }

    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
        &mut self.closures
    }

    pub unsafe fn pre_exec(
        &mut self,
        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
    ) {
        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
        unimplemented!();
    }

    pub fn stdin(&mut self, stdin: Stdio) {
        self.stdin = Some(stdin);
    }

    pub fn stdout(&mut self, stdout: Stdio) {
        self.stdout = Some(stdout);
    }

    pub fn stderr(&mut self, stderr: Stdio) {
        self.stderr = Some(stderr);
    }

    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
        &mut self.env
    }

    pub fn capture_env(&mut self) -> Option<CStringArray> {
        let maybe_env = self.env.capture_if_changed();
        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
    }
    #[allow(dead_code)]
    pub fn env_saw_path(&self) -> bool {
        self.env.have_changed_path()
    }

    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
                -> io::Result<(StdioPipes, ChildPipes)> {
        let null = Stdio::Null;
        let default_stdin = if needs_stdin {&default} else {&null};
        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
        let stdout = self.stdout.as_ref().unwrap_or(&default);
        let stderr = self.stderr.as_ref().unwrap_or(&default);
        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
        let ours = StdioPipes {
            stdin: our_stdin,
            stdout: our_stdout,
            stderr: our_stderr,
        };
        let theirs = ChildPipes {
            stdin: their_stdin,
            stdout: their_stdout,
            stderr: their_stderr,
        };
        Ok((ours, theirs))
    }
}

fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
        *saw_nul = true;
        CString::new("<string-with-nul>").unwrap()
    })
}

// Helper type to manage ownership of the strings within a C-style array.
pub struct CStringArray {
    items: Vec<CString>,
    ptrs: Vec<*const c_char>
}

impl CStringArray {
    pub fn with_capacity(capacity: usize) -> Self {
        let mut result = CStringArray {
            items: Vec::with_capacity(capacity),
            ptrs: Vec::with_capacity(capacity+1)
        };
        result.ptrs.push(ptr::null());
        result
    }
    pub fn push(&mut self, item: CString) {
        let l = self.ptrs.len();
        self.ptrs[l-1] = item.as_ptr();
        self.ptrs.push(ptr::null());
        self.items.push(item);
    }
    pub fn as_ptr(&self) -> *const *const c_char {
        self.ptrs.as_ptr()
    }
}

fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
    let mut result = CStringArray::with_capacity(env.len());
    for (k, v) in env {
        let mut k: OsString = k.into();

        // Reserve additional space for '=' and null terminator
        k.reserve_exact(v.len() + 2);
        k.push("=");
        k.push(&v);

        // Add the new entry into the array
        if let Ok(item) = CString::new(k.into_vec()) {
            result.push(item);
        } else {
            *saw_nul = true;
        }
    }

    result
}

impl Stdio {
    pub fn to_child_stdio(&self, readable: bool)
                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
        match *self {
            Stdio::Inherit => {
                Ok((ChildStdio::Inherit, None))
            },

            // Make sure that the source descriptors are not an stdio
            // descriptor, otherwise the order which we set the child's
            // descriptors may blow away a descriptor which we are hoping to
            // save. For example, suppose we want the child's stderr to be the
            // parent's stdout, and the child's stdout to be the parent's
            // stderr. No matter which we dup first, the second will get
            // overwritten prematurely.
            Stdio::Fd(ref fd) => {
                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
                } else {
                    Ok((ChildStdio::Explicit(fd.raw()), None))
                }
            }

            Stdio::MakePipe => {
                let (reader, writer) = pipe::anon_pipe()?;
                let (ours, theirs) = if readable {
                    (writer, reader)
                } else {
                    (reader, writer)
                };
                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
            }

            Stdio::Null => {
                let mut opts = OpenOptions::new();
                opts.read(readable);
                opts.write(!readable);
                let path = unsafe {
                    CStr::from_ptr("/null\0".as_ptr() as *const _)
                };
                let fd = File::open_c(&path, &opts)?;
                Ok((ChildStdio::Owned(fd.into_fd()), None))
            }
        }
    }
}

impl From<AnonPipe> for Stdio {
    fn from(pipe: AnonPipe) -> Stdio {
        Stdio::Fd(pipe.into_fd())
    }
}

impl From<File> for Stdio {
    fn from(file: File) -> Stdio {
        Stdio::Fd(file.into_fd())
    }
}

impl ChildStdio {
    pub fn fd(&self) -> Option<c_int> {
        match *self {
            ChildStdio::Inherit => None,
            ChildStdio::Explicit(fd) => Some(fd),
            ChildStdio::Owned(ref fd) => Some(fd.raw()),
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)?;
        for arg in &self.args {
            write!(f, " {:?}", arg)?;
        }
        Ok(())
    }
}

/// Unix exit statuses
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(c_int);

impl ExitStatus {
    pub fn new(status: c_int) -> ExitStatus {
        ExitStatus(status)
    }

    fn exited(&self) -> bool {
        /*unsafe*/ { libc::WIFEXITED(self.0) }
    }

    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        if self.exited() {
            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
        } else {
            None
        }
    }

    pub fn signal(&self) -> Option<i32> {
        if !self.exited() {
            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
        } else {
            None
        }
    }
}

impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(code) = self.code() {
            write!(f, "exit code: {}", code)
        } else {
            let signal = self.signal().unwrap();
            write!(f, "signal: {}", signal)
        }
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(u8);

impl ExitCode {
    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);

    #[inline]
    pub fn as_i32(&self) -> i32 {
        self.0 as i32
    }
}
<|endoftext|>


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

//! Implements sequential traversals over the DOM and flow trees.

use app_units::Au;
use context::{LayoutContext, SharedLayoutContext};
use euclid::point::Point2D;
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
use flow_ref::{self, FlowRef};
use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent;
use style::traversal::DomTraversalContext;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
use traversal::{BubbleISizes, BuildDisplayList, ComputeAbsolutePositions, PostorderNodeMutTraversal};
use util::opts;
use wrapper::LayoutNode;

pub fn traverse_dom_preorder<'ln, N, C>(root: N,
                                        shared: &C::SharedContext)
                                        where N: LayoutNode<'ln>,
                                              C: DomTraversalContext<'ln, N> {
    fn doit<'a, 'ln, N, C>(context: &'a C, node: N)
                           where N: LayoutNode<'ln>, C: DomTraversalContext<'ln, N> {
        context.process_preorder(node);

        for kid in node.children() {
            doit::<N, C>(context, kid);
        }

        context.process_postorder(node);
    }

    let context = C::new(shared, root.opaque());
    doit::<N, C>(&context, root);
}

pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) {
        if !traversal.should_process(flow) {
            return
        }

        traversal.process(flow, level);

        for kid in flow::mut_base(flow).children.iter_mut() {
            doit(kid, level + 1, traversal)
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);
    let mut traversal = ResolveGeneratedContent::new(&layout_context);
    doit(flow_ref::deref_mut(root), 0, &mut traversal)
}

pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
                                   shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow,
            assign_inline_sizes: AssignISizes,
            assign_block_sizes: AssignBSizesAndStoreOverflow) {
        if assign_inline_sizes.should_process(flow) {
            assign_inline_sizes.process(flow);
        }

        for kid in flow::child_iter(flow) {
            doit(kid, assign_inline_sizes, assign_block_sizes);
        }

        if assign_block_sizes.should_process(flow) {
            assign_block_sizes.process(flow);
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);

    let root = flow_ref::deref_mut(root);

    if opts::get().bubble_inline_sizes_separately {
        let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
        {
            let root: &mut Flow = root;
            root.traverse_postorder(&bubble_inline_sizes);
        }
    }

    let assign_inline_sizes = AssignISizes                 { layout_context: &layout_context };
    let assign_block_sizes  = AssignBSizesAndStoreOverflow { layout_context: &layout_context };

    doit(root, assign_inline_sizes, assign_block_sizes);
}

pub fn build_display_list_for_subtree(root: &mut FlowRef,
                                      shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow,
            compute_absolute_positions: ComputeAbsolutePositions,
            build_display_list: BuildDisplayList) {
        if compute_absolute_positions.should_process(flow) {
            compute_absolute_positions.process(flow);
        }

        for kid in flow::mut_base(flow).child_iter() {
            doit(kid, compute_absolute_positions, build_display_list);
        }

        if build_display_list.should_process(flow) {
            build_display_list.process(flow);
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);
    let compute_absolute_positions = ComputeAbsolutePositions { layout_context: &layout_context };
    let build_display_list         = BuildDisplayList         { layout_context: &layout_context };

    doit(flow_ref::deref_mut(root), compute_absolute_positions, build_display_list);
}

pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
                                                       iterator: &mut FragmentBorderBoxIterator) {
    fn doit(flow: &mut Flow,
            level: i32,
            iterator: &mut FragmentBorderBoxIterator,
            stacking_context_position: &Point2D<Au>) {
        flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);

        for kid in flow::mut_base(flow).child_iter() {
            let stacking_context_position =
                if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
                    let margin = Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0));
                    *stacking_context_position + flow::base(kid).stacking_relative_position + margin
                } else {
                    *stacking_context_position
                };

            // FIXME(#2795): Get the real container size.
            doit(kid, level + 1, iterator, &stacking_context_position);
        }
    }

    doit(flow_ref::deref_mut(root), 0, iterator, &Point2D::zero());
}
<commit_msg>Make sequential traversal operate on TNode instead of LayoutNode.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements sequential traversals over the DOM and flow trees.

use app_units::Au;
use context::{LayoutContext, SharedLayoutContext};
use euclid::point::Point2D;
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
use flow_ref::{self, FlowRef};
use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent;
use style::dom::TNode;
use style::traversal::DomTraversalContext;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
use traversal::{BubbleISizes, BuildDisplayList, ComputeAbsolutePositions, PostorderNodeMutTraversal};
use util::opts;

pub fn traverse_dom_preorder<'ln, N, C>(root: N,
                                        shared: &C::SharedContext)
                                        where N: TNode<'ln>,
                                              C: DomTraversalContext<'ln, N> {
    fn doit<'a, 'ln, N, C>(context: &'a C, node: N)
                           where N: TNode<'ln>, C: DomTraversalContext<'ln, N> {
        context.process_preorder(node);

        for kid in node.children() {
            doit::<N, C>(context, kid);
        }

        context.process_postorder(node);
    }

    let context = C::new(shared, root.opaque());
    doit::<N, C>(&context, root);
}

pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) {
        if !traversal.should_process(flow) {
            return
        }

        traversal.process(flow, level);

        for kid in flow::mut_base(flow).children.iter_mut() {
            doit(kid, level + 1, traversal)
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);
    let mut traversal = ResolveGeneratedContent::new(&layout_context);
    doit(flow_ref::deref_mut(root), 0, &mut traversal)
}

pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
                                   shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow,
            assign_inline_sizes: AssignISizes,
            assign_block_sizes: AssignBSizesAndStoreOverflow) {
        if assign_inline_sizes.should_process(flow) {
            assign_inline_sizes.process(flow);
        }

        for kid in flow::child_iter(flow) {
            doit(kid, assign_inline_sizes, assign_block_sizes);
        }

        if assign_block_sizes.should_process(flow) {
            assign_block_sizes.process(flow);
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);

    let root = flow_ref::deref_mut(root);

    if opts::get().bubble_inline_sizes_separately {
        let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
        {
            let root: &mut Flow = root;
            root.traverse_postorder(&bubble_inline_sizes);
        }
    }

    let assign_inline_sizes = AssignISizes                 { layout_context: &layout_context };
    let assign_block_sizes  = AssignBSizesAndStoreOverflow { layout_context: &layout_context };

    doit(root, assign_inline_sizes, assign_block_sizes);
}

pub fn build_display_list_for_subtree(root: &mut FlowRef,
                                      shared_layout_context: &SharedLayoutContext) {
    fn doit(flow: &mut Flow,
            compute_absolute_positions: ComputeAbsolutePositions,
            build_display_list: BuildDisplayList) {
        if compute_absolute_positions.should_process(flow) {
            compute_absolute_positions.process(flow);
        }

        for kid in flow::mut_base(flow).child_iter() {
            doit(kid, compute_absolute_positions, build_display_list);
        }

        if build_display_list.should_process(flow) {
            build_display_list.process(flow);
        }
    }

    let layout_context = LayoutContext::new(shared_layout_context);
    let compute_absolute_positions = ComputeAbsolutePositions { layout_context: &layout_context };
    let build_display_list         = BuildDisplayList         { layout_context: &layout_context };

    doit(flow_ref::deref_mut(root), compute_absolute_positions, build_display_list);
}

pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
                                                       iterator: &mut FragmentBorderBoxIterator) {
    fn doit(flow: &mut Flow,
            level: i32,
            iterator: &mut FragmentBorderBoxIterator,
            stacking_context_position: &Point2D<Au>) {
        flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);

        for kid in flow::mut_base(flow).child_iter() {
            let stacking_context_position =
                if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
                    let margin = Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0));
                    *stacking_context_position + flow::base(kid).stacking_relative_position + margin
                } else {
                    *stacking_context_position
                };

            // FIXME(#2795): Get the real container size.
            doit(kid, level + 1, iterator, &stacking_context_position);
        }
    }

    doit(flow_ref::deref_mut(root), 0, iterator, &Point2D::zero());
}
<|endoftext|>


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

use core::nonzero::NonZero;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::VRPoseBinding;
use dom::bindings::codegen::Bindings::VRPoseBinding::VRPoseMethods;
use dom::bindings::js::Root;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::globalscope::GlobalScope;
use js::jsapi::{Heap, JSContext, JSObject};
use js::typedarray::Float32Array;
use std::ptr;
use webvr_traits::webvr;

#[dom_struct]
pub struct VRPose {
    reflector_: Reflector,
    position: DOMRefCell<Heap<*mut JSObject>>,
    orientation: DOMRefCell<Heap<*mut JSObject>>,
    linear_vel: DOMRefCell<Heap<*mut JSObject>>,
    angular_vel: DOMRefCell<Heap<*mut JSObject>>,
    linear_acc: DOMRefCell<Heap<*mut JSObject>>,
    angular_acc: DOMRefCell<Heap<*mut JSObject>>
}

#[allow(unsafe_code)]
unsafe fn update_or_create_typed_array(cx: *mut JSContext,
                      src: Option<&[f32]>,
                      dst: &DOMRefCell<Heap<*mut JSObject>>) {
    let dst = dst.borrow();
    match src {
        Some(ref data) => {
            if dst.get().is_null() {
                let _ = Float32Array::create(cx, data.len() as u32, src, dst.handle_mut());
            } else {
                typedarray!(in(cx) let array: Float32Array = dst.get());
                if let Ok(mut array) = array {
                    array.update(data);
                }
            }
        },
        None => {
            if !dst.get().is_null() {
                dst.set(ptr::null_mut());
            }
        }
    }
}

#[inline]
#[allow(unsafe_code)]
fn heap_to_option(heap: &DOMRefCell<Heap<*mut JSObject>>) -> Option<NonZero<*mut JSObject>> {
    let js_object = heap.borrow_mut().get();
    if js_object.is_null() {
        None
    } else {
        unsafe {
            Some(NonZero::new(js_object))
        }
    }
}

impl VRPose {
    fn new_inherited() -> VRPose {
        VRPose {
            reflector_: Reflector::new(),
            position: DOMRefCell::new(Heap::default()),
            orientation: DOMRefCell::new(Heap::default()),
            linear_vel: DOMRefCell::new(Heap::default()),
            angular_vel: DOMRefCell::new(Heap::default()),
            linear_acc: DOMRefCell::new(Heap::default()),
            angular_acc: DOMRefCell::new(Heap::default())
        }
    }

    pub fn new(global: &GlobalScope, pose: &webvr::VRPose) -> Root<VRPose> {
        let root = reflect_dom_object(box VRPose::new_inherited(),
                                      global,
                                      VRPoseBinding::Wrap);
        root.update(&pose);
        root
    }

    #[allow(unsafe_code)]
    pub fn update(&self, pose: &webvr::VRPose) {
        let cx = self.global().get_cx();
        unsafe {
            update_or_create_typed_array(cx, pose.position.as_ref().map(|v| &v[..]), &self.position);
            update_or_create_typed_array(cx, pose.orientation.as_ref().map(|v| &v[..]), &self.orientation);
            update_or_create_typed_array(cx, pose.linear_velocity.as_ref().map(|v| &v[..]), &self.linear_vel);
            update_or_create_typed_array(cx, pose.angular_velocity.as_ref().map(|v| &v[..]), &self.angular_vel);
            update_or_create_typed_array(cx, pose.linear_acceleration.as_ref().map(|v| &v[..]), &self.linear_acc);
            update_or_create_typed_array(cx, pose.angular_acceleration.as_ref().map(|v| &v[..]), &self.angular_acc);
        }
    }
}

impl VRPoseMethods for VRPose {
    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-position
    unsafe fn GetPosition(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.position)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-linearvelocity
    unsafe fn GetLinearVelocity(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.linear_vel)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-linearacceleration
    unsafe fn GetLinearAcceleration(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.linear_acc)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-orientation
    unsafe fn GetOrientation(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.orientation)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-angularvelocity
    unsafe fn GetAngularVelocity(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.angular_vel)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-angularacceleration
    unsafe fn GetAngularAcceleration(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.angular_acc)
    }
}
<commit_msg>Stop using DOMRefCell<Heap<..>>.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use core::nonzero::NonZero;
use dom::bindings::codegen::Bindings::VRPoseBinding;
use dom::bindings::codegen::Bindings::VRPoseBinding::VRPoseMethods;
use dom::bindings::js::Root;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::globalscope::GlobalScope;
use js::jsapi::{Heap, JSContext, JSObject};
use js::typedarray::Float32Array;
use std::ptr;
use webvr_traits::webvr;

#[dom_struct]
pub struct VRPose {
    reflector_: Reflector,
    position: Heap<*mut JSObject>,
    orientation: Heap<*mut JSObject>,
    linear_vel: Heap<*mut JSObject>,
    angular_vel: Heap<*mut JSObject>,
    linear_acc: Heap<*mut JSObject>,
    angular_acc: Heap<*mut JSObject>,
}

#[allow(unsafe_code)]
unsafe fn update_or_create_typed_array(cx: *mut JSContext,
                      src: Option<&[f32]>,
                      dst: &Heap<*mut JSObject>) {
    match src {
        Some(ref data) => {
            if dst.get().is_null() {
                let _ = Float32Array::create(cx, data.len() as u32, src, dst.handle_mut());
            } else {
                typedarray!(in(cx) let array: Float32Array = dst.get());
                if let Ok(mut array) = array {
                    array.update(data);
                }
            }
        },
        None => {
            if !dst.get().is_null() {
                dst.set(ptr::null_mut());
            }
        }
    }
}

#[inline]
#[allow(unsafe_code)]
fn heap_to_option(heap: &Heap<*mut JSObject>) -> Option<NonZero<*mut JSObject>> {
    let js_object = heap.get();
    if js_object.is_null() {
        None
    } else {
        unsafe {
            Some(NonZero::new(js_object))
        }
    }
}

impl VRPose {
    fn new_inherited() -> VRPose {
        VRPose {
            reflector_: Reflector::new(),
            position: Heap::default(),
            orientation: Heap::default(),
            linear_vel: Heap::default(),
            angular_vel: Heap::default(),
            linear_acc: Heap::default(),
            angular_acc: Heap::default(),
        }
    }

    pub fn new(global: &GlobalScope, pose: &webvr::VRPose) -> Root<VRPose> {
        let root = reflect_dom_object(box VRPose::new_inherited(),
                                      global,
                                      VRPoseBinding::Wrap);
        root.update(&pose);
        root
    }

    #[allow(unsafe_code)]
    pub fn update(&self, pose: &webvr::VRPose) {
        let cx = self.global().get_cx();
        unsafe {
            update_or_create_typed_array(cx, pose.position.as_ref().map(|v| &v[..]), &self.position);
            update_or_create_typed_array(cx, pose.orientation.as_ref().map(|v| &v[..]), &self.orientation);
            update_or_create_typed_array(cx, pose.linear_velocity.as_ref().map(|v| &v[..]), &self.linear_vel);
            update_or_create_typed_array(cx, pose.angular_velocity.as_ref().map(|v| &v[..]), &self.angular_vel);
            update_or_create_typed_array(cx, pose.linear_acceleration.as_ref().map(|v| &v[..]), &self.linear_acc);
            update_or_create_typed_array(cx, pose.angular_acceleration.as_ref().map(|v| &v[..]), &self.angular_acc);
        }
    }
}

impl VRPoseMethods for VRPose {
    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-position
    unsafe fn GetPosition(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.position)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-linearvelocity
    unsafe fn GetLinearVelocity(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.linear_vel)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-linearacceleration
    unsafe fn GetLinearAcceleration(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.linear_acc)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-orientation
    unsafe fn GetOrientation(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.orientation)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-angularvelocity
    unsafe fn GetAngularVelocity(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.angular_vel)
    }

    #[allow(unsafe_code)]
    // https://w3c.github.io/webvr/#dom-vrpose-angularacceleration
    unsafe fn GetAngularAcceleration(&self, _cx: *mut JSContext) -> Option<NonZero<*mut JSObject>> {
        heap_to_option(&self.angular_acc)
    }
}
<|endoftext|>