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

use crate::bundle::{self, Bundle, Exchange, Response, Uri};
use crate::prelude::*;
use cbor_event::Len;
use std::io::Write;

use cbor_event::se::Serializer;

struct CountWrite<W> {
    count: usize,
    inner: W,
}

impl<W> CountWrite<W> {
    fn new(inner: W) -> Self {
        CountWrite { count: 0, inner }
    }
}

impl<W: Write> Write for CountWrite<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.count += buf.len();
        self.inner.write(buf)
    }
    fn flush(&mut self) -> std::io::Result<()> {
        self.inner.flush()
    }
}

pub(crate) fn encode<W: Write + Sized>(bundle: &Bundle, write: W) -> Result<()> {
    Encoder::new(CountWrite::new(write)).encode(bundle)?;
    Ok(())
}

pub(crate) fn encode_to_vec(bundle: &Bundle) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    encode(bundle, &mut write)?;
    Ok(write)
}

struct Encoder<W: Write> {
    se: Serializer<W>,
}

trait Count {
    fn count(&self) -> usize;
}

impl<W: Write> Count for Serializer<CountWrite<W>> {
    fn count(&self) -> usize {
        // Use unsafe because Serializer.0 is private.
        // TODO: Avoid to use unsafe.
        let se_ptr: *const Serializer<CountWrite<W>> = self;
        let count_write_ptr = se_ptr.cast::<CountWrite<W>>();
        unsafe { (*count_write_ptr).count }
    }
}

impl<W: Write> Encoder<W> {
    fn new(write: W) -> Self {
        Encoder {
            // se: Serializer::new(CountWrite::new(write)),
            se: Serializer::new(write),
        }
    }

    fn write_magic(&mut self) -> Result<()> {
        self.se.write_bytes(bundle::HEADER_MAGIC_BYTES)?;
        Ok(())
    }

    fn write_version(&mut self, version: &bundle::Version) -> Result<()> {
        self.se.write_bytes(version.bytes())?;
        Ok(())
    }

    fn write_primary_url(&mut self, primary_url: &Uri) -> Result<()> {
        self.se.write_text(&primary_url.to_string())?;
        Ok(())
    }
}

impl<W: Write + Sized> Encoder<CountWrite<W>> {
    fn encode(&mut self, bundle: &Bundle) -> Result<()> {
        self.se
            .write_array(Len::Len(bundle::TOP_ARRAY_LEN as u64))?;
        self.write_magic()?;
        self.write_version(&bundle.version)?;
        self.write_primary_url(&bundle.primary_url)?;

        let sections = encode_sections(bundle)?;

        let section_length_cbor = encode_section_lengths(&sections)?;
        self.se.write_bytes(section_length_cbor)?;

        self.se.write_array(Len::Len(sections.len() as u64))?;
        for section in sections {
            self.se.write_raw_bytes(&section.bytes)?;
        }

        // Write the length of bytes
        self.se.write_unsigned_integer(self.se.count() as u64 + 8)?; // 8 is the length of u64.
        Ok(())
    }
}

struct Section {
    name: &'static str,
    bytes: Vec<u8>,
}

fn encode_sections(bundle: &Bundle) -> Result<Vec<Section>> {
    let mut sections = Vec::new();

    // manifest
    if let Some(uri) = &bundle.manifest {
        let bytes = encode_manifest_section(uri)?;
        sections.push(Section {
            name: "manifest",
            bytes,
        });
    };

    // responses
    let (response_section_bytes, response_locations) = encode_response_section(&bundle.exchanges)?;

    let response_section = Section {
        name: "responses",
        bytes: response_section_bytes,
    };

    // index from responses
    let index_section = Section {
        name: "index",
        bytes: encode_index_section(&response_locations)?,
    };

    sections.push(index_section);
    sections.push(response_section);
    Ok(sections)
}

fn encode_manifest_section(url: &Uri) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    let mut se = Serializer::new(&mut write);
    se.write_text(url.to_string())?;
    Ok(write)
}

struct ResponseLocation {
    uri: Uri,
    offset: usize,
    length: usize,
}

fn encode_response_section(exchanges: &[Exchange]) -> Result<(Vec<u8>, Vec<ResponseLocation>)> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(CountWrite::new(&mut bytes));

    se.write_array(Len::Len(exchanges.len() as u64))?;

    let mut response_locations = Vec::new();

    for exchange in exchanges {
        let offset = se.count();

        se.write_array(Len::Len(2))?;
        se.write_bytes(&encode_headers(&exchange.response)?)?;
        se.write_bytes(&exchange.response.body())?;

        response_locations.push(ResponseLocation {
            uri: exchange.request.uri().clone(),
            offset,
            length: se.count() - offset,
        });
    }

    Ok((bytes, response_locations))
}

fn encode_index_section(response_locations: &[ResponseLocation]) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(&mut bytes);

    se.write_map(Len::Len(response_locations.len() as u64))?;

    for response_location in response_locations {
        se.write_text(response_location.uri.to_string())?;
        se.write_array(Len::Len(3))?;
        // TODO: Support variants.
        se.write_bytes(b"")?;
        se.write_unsigned_integer(response_location.offset as u64)?;
        se.write_unsigned_integer(response_location.length as u64)?;
    }
    Ok(bytes)
}

fn encode_section_lengths(sections: &[Section]) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(&mut bytes);

    se.write_array(Len::Len((sections.len() * 2) as u64))?;
    for section in sections {
        se.write_text(section.name)?;
        se.write_unsigned_integer(section.bytes.len() as u64)?;
    }
    Ok(bytes)
}

fn encode_headers(response: &Response) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(&mut bytes);

    se.write_map(Len::Len((response.headers().len() + 1) as u64))?;

    // Write status
    se.write_bytes(b":status")?;
    se.write_bytes(response.status().as_u16().to_string().as_bytes())?;

    // Write headers
    for (name, value) in response.headers() {
        se.write_bytes(name.as_str().as_bytes())?;
        se.write_bytes(value.to_str()?.as_bytes())?;
    }
    Ok(bytes)
}
<commit_msg>Sort map keys in encoding<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::bundle::{self, Bundle, Exchange, Response, Uri};
use crate::prelude::*;
use cbor_event::Len;
use std::io::Write;

use cbor_event::se::Serializer;

struct CountWrite<W> {
    count: usize,
    inner: W,
}

impl<W> CountWrite<W> {
    fn new(inner: W) -> Self {
        CountWrite { count: 0, inner }
    }
}

impl<W: Write> Write for CountWrite<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.count += buf.len();
        self.inner.write(buf)
    }
    fn flush(&mut self) -> std::io::Result<()> {
        self.inner.flush()
    }
}

pub(crate) fn encode<W: Write + Sized>(bundle: &Bundle, write: W) -> Result<()> {
    Encoder::new(CountWrite::new(write)).encode(bundle)?;
    Ok(())
}

pub(crate) fn encode_to_vec(bundle: &Bundle) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    encode(bundle, &mut write)?;
    Ok(write)
}

struct Encoder<W: Write> {
    se: Serializer<W>,
}

trait Count {
    fn count(&self) -> usize;
}

impl<W: Write> Count for Serializer<CountWrite<W>> {
    fn count(&self) -> usize {
        // Use unsafe because Serializer.0 is private.
        // TODO: Avoid to use unsafe.
        let se_ptr: *const Serializer<CountWrite<W>> = self;
        let count_write_ptr = se_ptr.cast::<CountWrite<W>>();
        unsafe { (*count_write_ptr).count }
    }
}

impl<W: Write> Encoder<W> {
    fn new(write: W) -> Self {
        Encoder {
            // se: Serializer::new(CountWrite::new(write)),
            se: Serializer::new(write),
        }
    }

    fn write_magic(&mut self) -> Result<()> {
        self.se.write_bytes(bundle::HEADER_MAGIC_BYTES)?;
        Ok(())
    }

    fn write_version(&mut self, version: &bundle::Version) -> Result<()> {
        self.se.write_bytes(version.bytes())?;
        Ok(())
    }

    fn write_primary_url(&mut self, primary_url: &Uri) -> Result<()> {
        self.se.write_text(&primary_url.to_string())?;
        Ok(())
    }
}

impl<W: Write + Sized> Encoder<CountWrite<W>> {
    fn encode(&mut self, bundle: &Bundle) -> Result<()> {
        self.se
            .write_array(Len::Len(bundle::TOP_ARRAY_LEN as u64))?;
        self.write_magic()?;
        self.write_version(&bundle.version)?;
        self.write_primary_url(&bundle.primary_url)?;

        let sections = encode_sections(bundle)?;

        let section_length_cbor = encode_section_lengths(&sections)?;
        self.se.write_bytes(section_length_cbor)?;

        self.se.write_array(Len::Len(sections.len() as u64))?;
        for section in sections {
            self.se.write_raw_bytes(&section.bytes)?;
        }

        // Write the length of bytes
        self.se.write_unsigned_integer(self.se.count() as u64 + 8)?; // 8 is the length of u64.
        Ok(())
    }
}

struct Section {
    name: &'static str,
    bytes: Vec<u8>,
}

fn encode_sections(bundle: &Bundle) -> Result<Vec<Section>> {
    let mut sections = Vec::new();

    // manifest
    if let Some(uri) = &bundle.manifest {
        let bytes = encode_manifest_section(uri)?;
        sections.push(Section {
            name: "manifest",
            bytes,
        });
    };

    // responses
    let (response_section_bytes, response_locations) = encode_response_section(&bundle.exchanges)?;

    let response_section = Section {
        name: "responses",
        bytes: response_section_bytes,
    };

    // index from responses
    let index_section = Section {
        name: "index",
        bytes: encode_index_section(&response_locations)?,
    };

    sections.push(index_section);
    sections.push(response_section);
    Ok(sections)
}

fn encode_manifest_section(url: &Uri) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    let mut se = Serializer::new(&mut write);
    se.write_text(url.to_string())?;
    Ok(write)
}

struct ResponseLocation {
    uri: Uri,
    offset: usize,
    length: usize,
}

fn encode_response_section(exchanges: &[Exchange]) -> Result<(Vec<u8>, Vec<ResponseLocation>)> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(CountWrite::new(&mut bytes));

    se.write_array(Len::Len(exchanges.len() as u64))?;

    let mut response_locations = Vec::new();

    for exchange in exchanges {
        let offset = se.count();

        se.write_array(Len::Len(2))?;
        se.write_bytes(&encode_headers(&exchange.response)?)?;
        se.write_bytes(&exchange.response.body())?;

        response_locations.push(ResponseLocation {
            uri: exchange.request.uri().clone(),
            offset,
            length: se.count() - offset,
        });
    }

    Ok((bytes, response_locations))
}

fn encode_index_section(response_locations: &[ResponseLocation]) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    for response_location in response_locations {
        let mut key = Serializer::new(Vec::new());
        key.write_text(response_location.uri.to_string())?;

        let mut value = Serializer::new(Vec::new());
        value.write_array(Len::Len(3))?;
        // TODO: Support variants.
        value.write_bytes(b"")?;
        value.write_unsigned_integer(response_location.offset as u64)?;
        value.write_unsigned_integer(response_location.length as u64)?;

        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new(Vec::new());
    se.write_map(Len::Len(response_locations.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}

fn encode_section_lengths(sections: &[Section]) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(&mut bytes);

    se.write_array(Len::Len((sections.len() * 2) as u64))?;
    for section in sections {
        se.write_text(section.name)?;
        se.write_unsigned_integer(section.bytes.len() as u64)?;
    }
    Ok(bytes)
}

fn encode_headers(response: &Response) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    // Write status
    let mut key = Serializer::new(Vec::new());
    key.write_bytes(b":status")?;
    let mut value = Serializer::new(Vec::new());
    value.write_bytes(response.status().as_u16().to_string().as_bytes())?;
    map.insert(key.finalize(), value.finalize());

    // Write headers
    for (header_name, header_value) in response.headers() {
        let mut key = Serializer::new(Vec::new());
        key.write_bytes(header_name.as_str().as_bytes())?;
        let mut value = Serializer::new(Vec::new());
        value.write_bytes(header_value.to_str()?.as_bytes())?;
        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new(Vec::new());
    se.write_map(Len::Len(map.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;
<commit_msg>Export documented API from ffi module<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

pub use self::lua::lua_Alloc;
pub use self::lua::lua_CFunction;
pub use self::lua::lua_Ctx;
pub use self::lua::lua_Debug;
pub use self::lua::lua_Hook;
pub use self::lua::lua_Integer;
pub use self::lua::lua_KFunction;
pub use self::lua::lua_Number;
pub use self::lua::lua_Reader;
pub use self::lua::lua_State;
pub use self::lua::lua_Unsigned;
pub use self::lua::lua_Writer;

pub use self::lua::lua_absindex;
pub use self::lua::lua_arith;
pub use self::lua::lua_atpanic;
pub use self::lua::lua_call;
pub use self::lua::lua_callk;
pub use self::lua::lua_checkstack;
pub use self::lua::lua_close;
pub use self::lua::lua_compare;
pub use self::lua::lua_concat;
pub use self::lua::lua_copy;
pub use self::lua::lua_createtable;
pub use self::lua::lua_dump;
pub use self::lua::lua_error;
pub use self::lua::lua_gc;
pub use self::lua::lua_getallocf;
pub use self::lua::lua_getextraspace;
pub use self::lua::lua_getfield;
pub use self::lua::lua_getglobal;
pub use self::lua::lua_gethook;
pub use self::lua::lua_gethookcount;
pub use self::lua::lua_gethookmask;
pub use self::lua::lua_getinfo;
pub use self::lua::lua_getlocal;
pub use self::lua::lua_getmetatable;
pub use self::lua::lua_getstack;
pub use self::lua::lua_gettable;
pub use self::lua::lua_gettop;
pub use self::lua::lua_getupvalue;
pub use self::lua::lua_getuservalue;
pub use self::lua::lua_insert;
pub use self::lua::lua_isboolean;
pub use self::lua::lua_iscfunction;
pub use self::lua::lua_isfunction;
pub use self::lua::lua_isinteger;
pub use self::lua::lua_islightuserdata;
pub use self::lua::lua_isnil;
pub use self::lua::lua_isnone;
pub use self::lua::lua_isnoneornil;
pub use self::lua::lua_isnumber;
pub use self::lua::lua_isstring;
pub use self::lua::lua_istable;
pub use self::lua::lua_isthread;
pub use self::lua::lua_isuserdata;
pub use self::lua::lua_isyieldable;
pub use self::lua::lua_len;
pub use self::lua::lua_load;
pub use self::lua::lua_newstate;
pub use self::lua::lua_newtable;
pub use self::lua::lua_newthread;
pub use self::lua::lua_newuserdata;
pub use self::lua::lua_next;
pub use self::luaconf::lua_numtointeger;
pub use self::lua::lua_pcall;
pub use self::lua::lua_pcallk;
pub use self::lua::lua_pop;
pub use self::lua::lua_pushboolean;
pub use self::lua::lua_pushcclosure;
pub use self::lua::lua_pushcfunction;
pub use self::lua::lua_pushfstring;
pub use self::lua::lua_pushglobaltable;
pub use self::lua::lua_pushinteger;
pub use self::lua::lua_pushlightuserdata;
pub use self::lua::lua_pushliteral;
pub use self::lua::lua_pushlstring;
pub use self::lua::lua_pushnil;
pub use self::lua::lua_pushnumber;
pub use self::lua::lua_pushstring;
pub use self::lua::lua_pushthread;
pub use self::lua::lua_pushvalue;
//pub use self::lua::lua_pushvfstring; -- not implemented
pub use self::lua::lua_rawequal;
pub use self::lua::lua_rawget;
pub use self::lua::lua_rawgeti;
pub use self::lua::lua_rawgetp;
pub use self::lua::lua_rawlen;
pub use self::lua::lua_rawset;
pub use self::lua::lua_rawseti;
pub use self::lua::lua_rawsetp;
pub use self::lua::lua_register;
pub use self::lua::lua_remove;
pub use self::lua::lua_replace;
pub use self::lua::lua_resume;
pub use self::lua::lua_rotate;
pub use self::lua::lua_setallocf;
pub use self::lua::lua_setfield;
pub use self::lua::lua_setglobal;
pub use self::lua::lua_sethook;
pub use self::lua::lua_setlocal;
pub use self::lua::lua_setmetatable;
pub use self::lua::lua_settable;
pub use self::lua::lua_settop;
pub use self::lua::lua_setupvalue;
pub use self::lua::lua_setuservalue;
pub use self::lua::lua_status;
pub use self::lua::lua_strtonum;
pub use self::lua::lua_toboolean;
pub use self::lua::lua_tocfunction;
pub use self::lua::lua_tointeger;
pub use self::lua::lua_tointegerx;
pub use self::lua::lua_tolstring;
pub use self::lua::lua_tonumber;
pub use self::lua::lua_tonumberx;
pub use self::lua::lua_topointer;
pub use self::lua::lua_tostring;
pub use self::lua::lua_tothread;
pub use self::lua::lua_touserdata;
pub use self::lua::lua_type;
pub use self::lua::lua_typename;
pub use self::lua::lua_upvalueid;
pub use self::lua::lua_upvalueindex;
pub use self::lua::lua_upvaluejoin;
pub use self::lua::lua_version;
pub use self::lua::lua_xmove;
pub use self::lua::lua_yield;
pub use self::lua::lua_yieldk;

pub use self::lauxlib::luaL_Buffer;
pub use self::lauxlib::luaL_Reg;
pub use self::lauxlib::luaL_Stream;

pub use self::lauxlib::luaL_addchar;
pub use self::lauxlib::luaL_addlstring;
pub use self::lauxlib::luaL_addsize;
pub use self::lauxlib::luaL_addstring;
pub use self::lauxlib::luaL_addvalue;
pub use self::lauxlib::luaL_argcheck;
pub use self::lauxlib::luaL_argerror;
pub use self::lauxlib::luaL_buffinit;
pub use self::lauxlib::luaL_buffinitsize;
pub use self::lauxlib::luaL_callmeta;
pub use self::lauxlib::luaL_checkany;
pub use self::lauxlib::luaL_checkint;
pub use self::lauxlib::luaL_checkinteger;
pub use self::lauxlib::luaL_checklong;
pub use self::lauxlib::luaL_checklstring;
pub use self::lauxlib::luaL_checknumber;
pub use self::lauxlib::luaL_checkoption;
pub use self::lauxlib::luaL_checkstack;
pub use self::lauxlib::luaL_checkstring;
pub use self::lauxlib::luaL_checktype;
pub use self::lauxlib::luaL_checkudata;
pub use self::lauxlib::luaL_checkversion;
pub use self::lauxlib::luaL_dofile;
pub use self::lauxlib::luaL_dostring;
pub use self::lauxlib::luaL_error;
pub use self::lauxlib::luaL_execresult;
pub use self::lauxlib::luaL_fileresult;
pub use self::lauxlib::luaL_getmetafield;
pub use self::lauxlib::luaL_getmetatable;
pub use self::lauxlib::luaL_getsubtable;
pub use self::lauxlib::luaL_gsub;
pub use self::lauxlib::luaL_len;
pub use self::lauxlib::luaL_loadbuffer;
pub use self::lauxlib::luaL_loadbufferx;
pub use self::lauxlib::luaL_loadfile;
pub use self::lauxlib::luaL_loadfilex;
pub use self::lauxlib::luaL_loadstring;
pub use self::lauxlib::luaL_newlib;
pub use self::lauxlib::luaL_newlibtable;
pub use self::lauxlib::luaL_newmetatable;
pub use self::lauxlib::luaL_newstate;
pub use self::lualib::luaL_openlibs;
pub use self::lauxlib::luaL_optint;
pub use self::lauxlib::luaL_optinteger;
pub use self::lauxlib::luaL_optlong;
pub use self::lauxlib::luaL_optlstring;
pub use self::lauxlib::luaL_optnumber;
pub use self::lauxlib::luaL_optstring;
pub use self::lauxlib::luaL_prepbuffer;
pub use self::lauxlib::luaL_prepbuffsize;
pub use self::lauxlib::luaL_pushresult;
pub use self::lauxlib::luaL_pushresultsize;
pub use self::lauxlib::luaL_ref;
pub use self::lauxlib::luaL_requiref;
pub use self::lauxlib::luaL_setfuncs;
pub use self::lauxlib::luaL_setmetatable;
pub use self::lauxlib::luaL_testudata;
pub use self::lauxlib::luaL_tolstring;
pub use self::lauxlib::luaL_traceback;
pub use self::lauxlib::luaL_typename;
pub use self::lauxlib::luaL_unref;
pub use self::lauxlib::luaL_where;

// commonly used constants from lua.h
pub use self::lua::{LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS};

pub use self::lua::{LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV};
pub use self::lua::{LUA_OPMOD, LUA_OPPOW, LUA_OPUNM};
pub use self::lua::{LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR};
pub use self::lua::{LUA_OPEQ, LUA_OPLT, LUA_OPLE};

pub use self::lua::{LUA_OK, LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR, LUA_ERRGCMM};

pub use self::lua::{LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE};
pub use self::lua::{LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA};

pub use self::lua::{LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT};

// constants from lauxlib.h
pub use self::lauxlib::{LUA_REFNIL, LUA_NOREF};

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;

<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use] extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;
use std::ffi::CStr;
use std::convert::AsRef;

use std::sync::mpsc::{Sender};

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent {
  paths: cf::CFMutableArrayRef,
  since_when: fs::FSEventStreamEventId,
  latency: cf::CFTimeInterval,
  flags: fs::FSEventStreamCreateFlags,
  sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
  pub event_id: u64,
  pub flag: StreamFlags,
  pub path: String,
}

pub type FsEventCallback = fn(Vec<Event>);

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
      let _d = write!(f, "MUST_SCAN_SUBDIRS ");
    }
    if self.contains(StreamFlags::USER_DROPPED) {
      let _d = write!(f, "USER_DROPPED ");
    }
    if self.contains(StreamFlags::KERNEL_DROPPED) {
      let _d = write!(f, "KERNEL_DROPPED ");
    }
    if self.contains(StreamFlags::IDS_WRAPPED) {
      let _d = write!(f, "IDS_WRAPPED ");
    }
    if self.contains(StreamFlags::HISTORY_DONE) {
      let _d = write!(f, "HISTORY_DONE ");
    }
    if self.contains(StreamFlags::ROOT_CHANGED) {
      let _d = write!(f, "ROOT_CHANGED ");
    }
    if self.contains(StreamFlags::MOUNT) {
      let _d = write!(f, "MOUNT ");
    }
    if self.contains(StreamFlags::UNMOUNT) {
      let _d = write!(f, "UNMOUNT ");
    }
    if self.contains(StreamFlags::ITEM_CREATED) {
      let _d = write!(f, "ITEM_CREATED ");
    }
    if self.contains(StreamFlags::ITEM_REMOVED) {
      let _d = write!(f, "ITEM_REMOVED ");
    }
    if self.contains(StreamFlags::INOTE_META_MOD) {
      let _d = write!(f, "INOTE_META_MOD ");
    }
    if self.contains(StreamFlags::ITEM_RENAMED) {
      let _d = write!(f, "ITEM_RENAMED ");
    }
    if self.contains(StreamFlags::ITEM_MODIFIED) {
      let _d = write!(f, "ITEM_MODIFIED ");
    }
    if self.contains(StreamFlags::FINDER_INFO_MOD) {
      let _d = write!(f, "FINDER_INFO_MOD ");
    }
    if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
      let _d = write!(f, "ITEM_CHANGE_OWNER ");
    }
    if self.contains(StreamFlags::ITEM_XATTR_MOD) {
      let _d = write!(f, "ITEM_XATTR_MOD ");
    }
    if self.contains(StreamFlags::IS_FILE) {
      let _d = write!(f, "IS_FILE ");
    }
    if self.contains(StreamFlags::IS_DIR) {
      let _d = write!(f, "IS_DIR ");
    }
    if self.contains(StreamFlags::IS_SYMLIMK) {
      let _d = write!(f, "IS_SYMLIMK ");
    }
    if self.contains(StreamFlags::OWN_EVENT) {
      let _d = write!(f, "OWN_EVENT ");
    }
    if self.contains(StreamFlags::IS_LAST_HARDLINK) {
      let _d = write!(f, "IS_LAST_HARDLINK ");
    }
    if self.contains(StreamFlags::IS_HARDLINK) {
      let _d = write!(f, "IS_HARDLINK ");
    }
    if self.contains(StreamFlags::ITEM_CLONED) {
      let
      _d = write!(f, "ITEM_CLONED ");
    }
    write!(f, "")
  }
}

pub fn is_api_available() -> (bool, String) {
  let ma = cf::system_version_major();
  let mi = cf::system_version_minor();

  if ma == 10 && mi < 5 {
    (false, "This version of OSX does not support the FSEvent library, cannot proceed".to_string())
  } else {
    (true, "ok".to_string())
  }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
  let ptr = info as *mut libc::c_void;
  fs::FSEventStreamContext {
    version: 0,
    info: ptr,
    retain: cf::NULL,
    copy_description: cf::NULL
  }
}

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

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
  pub fn new(sender: Sender<Event>) -> FsEvent {
    let fsevent: FsEvent;

    unsafe {
      fsevent = FsEvent{
        paths: cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks),
        since_when: fs::kFSEventStreamEventIdSinceNow,
        latency: 0.0,
        flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
        sender: sender,
      };
    }
    fsevent
  }

  // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
  pub fn append_path(&self,source: &str) -> Result<()> {
    unsafe {
      let mut err = ptr::null_mut();
      let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
      if !err.is_null() {
          let cf_str = cf::CFCopyDescription(err as cf::CFRef);
          let mut buf = [0; 1024];
          cf::CFStringGetCString(cf_str, buf.as_mut_ptr(), buf.len() as cf::CFIndex, cf::kCFStringEncodingUTF8);
          Err(Error { msg: CStr::from_ptr(buf.as_ptr()).to_str().unwrap_or("Unknown error").to_string() })
      } else {
          cf::CFArrayAppendValue(self.paths, cf_path);
          cf::CFRelease(cf_path);
          Ok(())
      }
    }
  }
  pub fn observe(&self) {
    let stream_context = default_stream_context(self);

    let cb = callback as *mut _;

    unsafe {
      let stream = fs::FSEventStreamCreate(cf::kCFAllocatorDefault,
       cb,
       &stream_context,
       self.paths,
       self.since_when,
       self.latency,
       self.flags);

      // fs::FSEventStreamShow(stream);

      fs::FSEventStreamScheduleWithRunLoop(stream,
        cf::CFRunLoopGetCurrent(),
        cf::kCFRunLoopDefaultMode);

      fs::FSEventStreamStart(stream);
      cf::CFRunLoopRun();

      fs::FSEventStreamFlushSync(stream);
      fs::FSEventStreamStop(stream);

    }
  }
}

#[allow(unused_variables)]
pub unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,      // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,  // const FSEventStreamEventId eventIds[]
  ) {
  let num = num_events as usize;
  let e_ptr = event_flags as *mut u32;
  let i_ptr = event_ids as *mut u64;
  let fs_event = info as *mut FsEvent;

  let paths: &[*const libc::c_char] = std::mem::transmute(slice::from_raw_parts(event_paths, num));
  let flags = from_raw_parts_mut(e_ptr, num);
  let ids = from_raw_parts_mut(i_ptr, num);

  for p in 0..num {
    let i = CStr::from_ptr(paths[p]).to_bytes();
    let path = from_utf8(i).expect("Invalid UTF8 string.");
    let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32)
    .expect(format!("Unable to decode StreamFlags: {} for {}", flags[p] as u32, path).as_ref());
    // println!("{}: {}", ids[p], flag);

    let event = Event{event_id: ids[p], flag: flag, path: path.to_string()};
    let _s = (*fs_event).sender.send(event);
  }
}
<commit_msg>clippy: Remove redundant struct field names.<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use] extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;
use std::ffi::CStr;
use std::convert::AsRef;

use std::sync::mpsc::{Sender};

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent {
  paths: cf::CFMutableArrayRef,
  since_when: fs::FSEventStreamEventId,
  latency: cf::CFTimeInterval,
  flags: fs::FSEventStreamCreateFlags,
  sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
  pub event_id: u64,
  pub flag: StreamFlags,
  pub path: String,
}

pub type FsEventCallback = fn(Vec<Event>);

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
      let _d = write!(f, "MUST_SCAN_SUBDIRS ");
    }
    if self.contains(StreamFlags::USER_DROPPED) {
      let _d = write!(f, "USER_DROPPED ");
    }
    if self.contains(StreamFlags::KERNEL_DROPPED) {
      let _d = write!(f, "KERNEL_DROPPED ");
    }
    if self.contains(StreamFlags::IDS_WRAPPED) {
      let _d = write!(f, "IDS_WRAPPED ");
    }
    if self.contains(StreamFlags::HISTORY_DONE) {
      let _d = write!(f, "HISTORY_DONE ");
    }
    if self.contains(StreamFlags::ROOT_CHANGED) {
      let _d = write!(f, "ROOT_CHANGED ");
    }
    if self.contains(StreamFlags::MOUNT) {
      let _d = write!(f, "MOUNT ");
    }
    if self.contains(StreamFlags::UNMOUNT) {
      let _d = write!(f, "UNMOUNT ");
    }
    if self.contains(StreamFlags::ITEM_CREATED) {
      let _d = write!(f, "ITEM_CREATED ");
    }
    if self.contains(StreamFlags::ITEM_REMOVED) {
      let _d = write!(f, "ITEM_REMOVED ");
    }
    if self.contains(StreamFlags::INOTE_META_MOD) {
      let _d = write!(f, "INOTE_META_MOD ");
    }
    if self.contains(StreamFlags::ITEM_RENAMED) {
      let _d = write!(f, "ITEM_RENAMED ");
    }
    if self.contains(StreamFlags::ITEM_MODIFIED) {
      let _d = write!(f, "ITEM_MODIFIED ");
    }
    if self.contains(StreamFlags::FINDER_INFO_MOD) {
      let _d = write!(f, "FINDER_INFO_MOD ");
    }
    if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
      let _d = write!(f, "ITEM_CHANGE_OWNER ");
    }
    if self.contains(StreamFlags::ITEM_XATTR_MOD) {
      let _d = write!(f, "ITEM_XATTR_MOD ");
    }
    if self.contains(StreamFlags::IS_FILE) {
      let _d = write!(f, "IS_FILE ");
    }
    if self.contains(StreamFlags::IS_DIR) {
      let _d = write!(f, "IS_DIR ");
    }
    if self.contains(StreamFlags::IS_SYMLIMK) {
      let _d = write!(f, "IS_SYMLIMK ");
    }
    if self.contains(StreamFlags::OWN_EVENT) {
      let _d = write!(f, "OWN_EVENT ");
    }
    if self.contains(StreamFlags::IS_LAST_HARDLINK) {
      let _d = write!(f, "IS_LAST_HARDLINK ");
    }
    if self.contains(StreamFlags::IS_HARDLINK) {
      let _d = write!(f, "IS_HARDLINK ");
    }
    if self.contains(StreamFlags::ITEM_CLONED) {
      let
      _d = write!(f, "ITEM_CLONED ");
    }
    write!(f, "")
  }
}

pub fn is_api_available() -> (bool, String) {
  let ma = cf::system_version_major();
  let mi = cf::system_version_minor();

  if ma == 10 && mi < 5 {
    (false, "This version of OSX does not support the FSEvent library, cannot proceed".to_string())
  } else {
    (true, "ok".to_string())
  }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
  let ptr = info as *mut libc::c_void;
  fs::FSEventStreamContext {
    version: 0,
    info: ptr,
    retain: cf::NULL,
    copy_description: cf::NULL
  }
}

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

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
  pub fn new(sender: Sender<Event>) -> FsEvent {
    let fsevent: FsEvent;

    unsafe {
      fsevent = FsEvent{
        paths: cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks),
        since_when: fs::kFSEventStreamEventIdSinceNow,
        latency: 0.0,
        flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
        sender,
      };
    }
    fsevent
  }

  // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
  pub fn append_path(&self,source: &str) -> Result<()> {
    unsafe {
      let mut err = ptr::null_mut();
      let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
      if !err.is_null() {
          let cf_str = cf::CFCopyDescription(err as cf::CFRef);
          let mut buf = [0; 1024];
          cf::CFStringGetCString(cf_str, buf.as_mut_ptr(), buf.len() as cf::CFIndex, cf::kCFStringEncodingUTF8);
          Err(Error { msg: CStr::from_ptr(buf.as_ptr()).to_str().unwrap_or("Unknown error").to_string() })
      } else {
          cf::CFArrayAppendValue(self.paths, cf_path);
          cf::CFRelease(cf_path);
          Ok(())
      }
    }
  }
  pub fn observe(&self) {
    let stream_context = default_stream_context(self);

    let cb = callback as *mut _;

    unsafe {
      let stream = fs::FSEventStreamCreate(cf::kCFAllocatorDefault,
       cb,
       &stream_context,
       self.paths,
       self.since_when,
       self.latency,
       self.flags);

      // fs::FSEventStreamShow(stream);

      fs::FSEventStreamScheduleWithRunLoop(stream,
        cf::CFRunLoopGetCurrent(),
        cf::kCFRunLoopDefaultMode);

      fs::FSEventStreamStart(stream);
      cf::CFRunLoopRun();

      fs::FSEventStreamFlushSync(stream);
      fs::FSEventStreamStop(stream);

    }
  }
}

#[allow(unused_variables)]
pub unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,      // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void, // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,  // const FSEventStreamEventId eventIds[]
  ) {
  let num = num_events as usize;
  let e_ptr = event_flags as *mut u32;
  let i_ptr = event_ids as *mut u64;
  let fs_event = info as *mut FsEvent;

  let paths: &[*const libc::c_char] = std::mem::transmute(slice::from_raw_parts(event_paths, num));
  let flags = from_raw_parts_mut(e_ptr, num);
  let ids = from_raw_parts_mut(i_ptr, num);

  for p in 0..num {
    let i = CStr::from_ptr(paths[p]).to_bytes();
    let path = from_utf8(i).expect("Invalid UTF8 string.");
    let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32)
    .expect(format!("Unable to decode StreamFlags: {} for {}", flags[p] as u32, path).as_ref());
    // println!("{}: {}", ids[p], flag);

    let event = Event{event_id: ids[p], flag, path: path.to_string()};
    let _s = (*fs_event).sender.send(event);
  }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate ansi_term;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate nix;
extern crate protobuf;
extern crate record_query;
extern crate rustc_serialize;
extern crate serde_protobuf;

use std::env;
use std::io;
use std::path;

use record_query as rq;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

docopt!(pub Args derive Debug, concat!("
rq - record query v", env!("CARGO_PKG_VERSION"), "

A tool for manipulating data records.

Records are read from stdin, processed, and written to stdout.  The tool accepts
a query in the custom rq query language as its main command-line arguments.

See 'man rq' for in-depth documentation.

Usage:
  rq (--help|--version)
  rq [-j|-c|-p <type>] [-J|-C|-P <type>] [-l <level>|-q] [--] [<query>]
  rq [-l <level>|-q] protobuf add <schema> [--base <path>]

Options:
  --help
      Show this screen.
  --version
      Show the program name and version.

  -j, --input-json
      Input is white-space separated JSON values.
  -J, --output-json
      Output should be formatted as JSON values.
  -c, --input-cbor
      Input is a series of CBOR values.
  -C, --output-cbor
      Output is a series of CBOR values.
  -p <type>, --input-protobuf <type>
      Input is a single protocol buffer object.  The argument refers to the
      fully qualified name of the message type (including the leading '.').
  -P <type>, --output-protobuf <type>
      Output should be formatted as protocol buffer objects.  The argument
      refers to the fully qualified name of the message type (including the
      leading '.').

  <query>
      A query indicating how to transform each record.

  --base <path>
      Directories are significant when dealing with protocol buffer
      schemas.  This specifies the base directory used to normalize schema
      file paths [default: .]

  -l <level>, --log <level>
      Display log messages at and above the specified log level.  The value can
      be one of 'off', 'error', 'warn', 'info', 'debug' or 'trace'.
  -q, --quiet
      Log nothing (alias for '-l off').
"),
        flag_input_protobuf: Option<String>,
        flag_output_protobuf: Option<String>,
        flag_log: Option<String>,
        flag_base: Option<String>);

fn main() {
    let args: Args = Args::docopt()
                         .version(Some(VERSION.to_owned()))
                         .decode()
                         .unwrap_or_else(|e| e.exit());

    main_with_args(&args).unwrap();
}

fn main_with_args(args: &Args) -> rq::error::Result<()> {
    setup_log(args.flag_log.as_ref().map(String::as_ref), args.flag_quiet);

    let paths = rq::config::Paths::new().unwrap();

    if args.cmd_protobuf {
        if args.cmd_add {
            let schema = path::Path::new(&args.arg_schema);
            let base = path::Path::new(if let Some(ref b) = args.flag_base {
                b.as_str()
            } else {
                "."
            });
            rq::proto_index::add_file(&paths, base, schema)
        } else {
            unreachable!()
        }
    } else {
        run(&args, &paths)
    }
}

fn run(args: &Args, paths: &rq::config::Paths) -> rq::error::Result<()> {

    let stdin = io::stdin();
    let mut input = stdin.lock();

    if let Some(ref name) = args.flag_input_protobuf {
        let proto_descriptors = try!(load_descriptors(&paths));
        let stream = protobuf::CodedInputStream::new(&mut input);
        let source = try!(rq::value::protobuf::source(&proto_descriptors, name, stream));
        run_source(args, paths, source)
    } else if args.flag_input_cbor {
        let source = rq::value::cbor::source(&mut input);
        run_source(args, paths, source)
    } else {
        let source = rq::value::json::source(&mut input);
        run_source(args, paths, source)
    }
}

fn run_source<I>(args: &Args, paths: &rq::config::Paths, source: I) -> rq::error::Result<()>
    where I: rq::value::Source
{
    let mut output = io::stdout();

    if let Some(_) = args.flag_output_protobuf {
        Err(rq::error::Error::unimplemented("protobuf serialization".to_owned()))
    } else if args.flag_output_cbor {
        let sink = rq::value::cbor::sink(&mut output);
        run_source_sink(args, paths, source, sink)
    } else {
        let sink = rq::value::json::sink(&mut output);
        run_source_sink(args, paths, source, sink)
    }
}

fn run_source_sink<I, O>(args: &Args,
                         _paths: &rq::config::Paths,
                         source: I,
                         mut sink: O)
                         -> rq::error::Result<()>
    where I: rq::value::Source,
          O: rq::value::Sink
{
    use record_query::value::Source;

    let query = rq::query::Query::parse(&args.arg_query);
    let query_context = rq::query::Context::new();
    let mut results = try!(query.evaluate(&query_context, source));
    while let Some(result) = try!(results.read()) {
        try!(sink.write(result));
    }
    Ok(())
}

fn load_descriptors(paths: &rq::config::Paths)
                    -> rq::error::Result<serde_protobuf::descriptor::Descriptors> {
    let descriptors_proto = try!(rq::proto_index::compile_descriptor_set(paths));
    Ok(serde_protobuf::descriptor::Descriptors::from_proto(&descriptors_proto))
}

fn setup_log(level: Option<&str>, quiet: bool) {
    use std::str::FromStr;
    use ansi_term::ANSIStrings;
    use ansi_term::Colour;
    use ansi_term::Style;
    use log::LogLevel;
    use log::LogLevelFilter;
    use nix::unistd;
    use nix::sys::ioctl;

    let normal = Style::new();

    let format = move |record: &log::LogRecord| {
        if unistd::isatty(ioctl::libc::STDERR_FILENO).unwrap_or(false) {
            let (front, back) = match record.level() {
                LogLevel::Error => (Colour::Red.normal(), Colour::Red.dimmed()),
                LogLevel::Warn => (Colour::Yellow.normal(), Colour::Yellow.dimmed()),
                LogLevel::Info => (Colour::Blue.normal(), Colour::Blue.dimmed()),
                LogLevel::Debug => (Colour::Purple.normal(), Colour::Purple.dimmed()),
                LogLevel::Trace => (Colour::White.dimmed(), Colour::Black.normal()),
            };

            let strings = &[back.paint("["),
                            front.paint(format!("{}", record.level())),
                            back.paint("]"),
                            normal.paint(" "),
                            back.paint("["),
                            front.paint(record.location().module_path()),
                            back.paint("]"),
                            normal.paint(" "),
                            back.paint(format!("{}", record.args()))];

            format!("{}", ANSIStrings(strings))
        } else {
            format!("[{}] [{}] {}",
                    record.level(),
                    record.location().module_path(),
                    record.args())
        }
    };

    let mut builder = env_logger::LogBuilder::new();

    let filter = if quiet {
        LogLevelFilter::Off
    } else if let Some(l) = level {
        LogLevelFilter::from_str(l).unwrap_or(LogLevelFilter::Info)
    } else {
        LogLevelFilter::Info
    };

    builder.format(format).filter(None, filter);

    if let Ok(spec) = env::var("RUST_LOG") {
        builder.parse(&spec);
    }

    builder.init().unwrap();
}

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

    fn parse_args(args: &[&str]) -> Args {
        let a = Args::docopt().argv(args).decode().unwrap();
        println!("{:?}", a);
        a
    }

    #[test]
    fn test_docopt_kitchen_sink() {
        let a = parse_args(&["rq", "-l", "info", "-jP", ".foo.Bar", "select x"]);
        assert!(a.flag_input_json);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
        assert_eq!(a.flag_log, Some("info".to_owned()));
        assert_eq!(a.arg_query, "select x");
    }

    #[test]
    fn test_docopt_no_args() {
        parse_args(&["rq"]);
    }

    #[test]
    #[should_panic(expected = "Help")]
    fn test_docopt_help() {
        parse_args(&["rq", "--help"]);
    }

    #[test]
    fn test_docopt_version() {
        let a = parse_args(&["rq", "--version"]);
        assert!(a.flag_version);
    }

    #[test]
    fn test_docopt_input_json() {
        let a = parse_args(&["rq", "-j"]);
        assert!(a.flag_input_json);
    }

    #[test]
    fn test_docopt_input_json_long() {
        let a = parse_args(&["rq", "--input-json"]);
        assert!(a.flag_input_json);
    }

    #[test]
    fn test_docopt_output_json() {
        let a = parse_args(&["rq", "-J"]);
        assert!(a.flag_output_json);
    }

    #[test]
    fn test_docopt_output_json_long() {
        let a = parse_args(&["rq", "--output-json"]);
        assert!(a.flag_output_json);
    }

    #[test]
    fn test_docopt_input_cbor() {
        let a = parse_args(&["rq", "-c"]);
        assert!(a.flag_input_cbor);
    }

    #[test]
    fn test_docopt_input_cbor_long() {
        let a = parse_args(&["rq", "--input-cbor"]);
        assert!(a.flag_input_cbor);
    }

    #[test]
    fn test_docopt_output_cbor() {
        let a = parse_args(&["rq", "-C"]);
        assert!(a.flag_output_cbor);
    }

    #[test]
    fn test_docopt_output_cbor_long() {
        let a = parse_args(&["rq", "--output-cbor"]);
        assert!(a.flag_output_cbor);
    }

    #[test]
    fn test_docopt_input_protobuf() {
        let a = parse_args(&["rq", "-p", ".foo.Bar"]);
        assert_eq!(a.flag_input_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_input_protobuf_long() {
        let a = parse_args(&["rq", "--input-protobuf", ".foo.Bar"]);
        assert_eq!(a.flag_input_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_output_protobuf() {
        let a = parse_args(&["rq", "-P", ".foo.Bar"]);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_output_protobuf_long() {
        let a = parse_args(&["rq", "--output-protobuf", ".foo.Bar"]);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    #[should_panic(expected = "NoMatch")]
    fn test_docopt_input_conflict() {
        parse_args(&["rq", "-jc"]);
    }

    #[test]
    #[should_panic(expected = "NoMatch")]
    fn test_docopt_output_conflict() {
        parse_args(&["rq", "-JC"]);
    }

    #[test]
    fn test_docopt_protobuf_add_schema() {
        let a = parse_args(&["rq", "-l", "info", "protobuf", "add", "schema.proto"]);
        assert_eq!(a.flag_log, Some("info".to_owned()));
        assert!(a.cmd_protobuf);
        assert!(a.cmd_add);
        assert_eq!(a.arg_schema, "schema.proto");
    }
}
<commit_msg>Make rq query required<commit_after>#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate ansi_term;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate nix;
extern crate protobuf;
extern crate record_query;
extern crate rustc_serialize;
extern crate serde_protobuf;

use std::env;
use std::io;
use std::path;

use record_query as rq;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

docopt!(pub Args derive Debug, concat!("
rq - record query v", env!("CARGO_PKG_VERSION"), "

A tool for manipulating data records.

Records are read from stdin, processed, and written to stdout.  The tool accepts
a query in the custom rq query language as its main command-line arguments.

See 'man rq' for in-depth documentation.

Usage:
  rq (--help|--version)
  rq [-j|-c|-p <type>] [-J|-C|-P <type>] [-l <level>|-q] [--] <query>
  rq [-l <level>|-q] protobuf add <schema> [--base <path>]

Options:
  --help
      Show this screen.
  --version
      Show the program name and version.

  -j, --input-json
      Input is white-space separated JSON values.
  -J, --output-json
      Output should be formatted as JSON values.
  -c, --input-cbor
      Input is a series of CBOR values.
  -C, --output-cbor
      Output is a series of CBOR values.
  -p <type>, --input-protobuf <type>
      Input is a single protocol buffer object.  The argument refers to the
      fully qualified name of the message type (including the leading '.').
  -P <type>, --output-protobuf <type>
      Output should be formatted as protocol buffer objects.  The argument
      refers to the fully qualified name of the message type (including the
      leading '.').

  <query>
      A query indicating how to transform each record.

  --base <path>
      Directories are significant when dealing with protocol buffer
      schemas.  This specifies the base directory used to normalize schema
      file paths [default: .]

  -l <level>, --log <level>
      Display log messages at and above the specified log level.  The value can
      be one of 'off', 'error', 'warn', 'info', 'debug' or 'trace'.
  -q, --quiet
      Log nothing (alias for '-l off').
"),
        flag_input_protobuf: Option<String>,
        flag_output_protobuf: Option<String>,
        flag_log: Option<String>,
        flag_base: Option<String>);

fn main() {
    let args: Args = Args::docopt()
                         .version(Some(VERSION.to_owned()))
                         .decode()
                         .unwrap_or_else(|e| e.exit());

    main_with_args(&args).unwrap();
}

fn main_with_args(args: &Args) -> rq::error::Result<()> {
    setup_log(args.flag_log.as_ref().map(String::as_ref), args.flag_quiet);

    let paths = rq::config::Paths::new().unwrap();

    if args.cmd_protobuf {
        if args.cmd_add {
            let schema = path::Path::new(&args.arg_schema);
            let base = path::Path::new(if let Some(ref b) = args.flag_base {
                b.as_str()
            } else {
                "."
            });
            rq::proto_index::add_file(&paths, base, schema)
        } else {
            unreachable!()
        }
    } else {
        run(&args, &paths)
    }
}

fn run(args: &Args, paths: &rq::config::Paths) -> rq::error::Result<()> {

    let stdin = io::stdin();
    let mut input = stdin.lock();

    if let Some(ref name) = args.flag_input_protobuf {
        let proto_descriptors = try!(load_descriptors(&paths));
        let stream = protobuf::CodedInputStream::new(&mut input);
        let source = try!(rq::value::protobuf::source(&proto_descriptors, name, stream));
        run_source(args, paths, source)
    } else if args.flag_input_cbor {
        let source = rq::value::cbor::source(&mut input);
        run_source(args, paths, source)
    } else {
        let source = rq::value::json::source(&mut input);
        run_source(args, paths, source)
    }
}

fn run_source<I>(args: &Args, paths: &rq::config::Paths, source: I) -> rq::error::Result<()>
    where I: rq::value::Source
{
    let mut output = io::stdout();

    if let Some(_) = args.flag_output_protobuf {
        Err(rq::error::Error::unimplemented("protobuf serialization".to_owned()))
    } else if args.flag_output_cbor {
        let sink = rq::value::cbor::sink(&mut output);
        run_source_sink(args, paths, source, sink)
    } else {
        let sink = rq::value::json::sink(&mut output);
        run_source_sink(args, paths, source, sink)
    }
}

fn run_source_sink<I, O>(args: &Args,
                         _paths: &rq::config::Paths,
                         source: I,
                         mut sink: O)
                         -> rq::error::Result<()>
    where I: rq::value::Source,
          O: rq::value::Sink
{
    use record_query::value::Source;

    let query = rq::query::Query::parse(&args.arg_query);
    let query_context = rq::query::Context::new();
    let mut results = try!(query.evaluate(&query_context, source));
    while let Some(result) = try!(results.read()) {
        try!(sink.write(result));
    }
    Ok(())
}

fn load_descriptors(paths: &rq::config::Paths)
                    -> rq::error::Result<serde_protobuf::descriptor::Descriptors> {
    let descriptors_proto = try!(rq::proto_index::compile_descriptor_set(paths));
    Ok(serde_protobuf::descriptor::Descriptors::from_proto(&descriptors_proto))
}

fn setup_log(level: Option<&str>, quiet: bool) {
    use std::str::FromStr;
    use ansi_term::ANSIStrings;
    use ansi_term::Colour;
    use ansi_term::Style;
    use log::LogLevel;
    use log::LogLevelFilter;
    use nix::unistd;
    use nix::sys::ioctl;

    let normal = Style::new();

    let format = move |record: &log::LogRecord| {
        if unistd::isatty(ioctl::libc::STDERR_FILENO).unwrap_or(false) {
            let (front, back) = match record.level() {
                LogLevel::Error => (Colour::Red.normal(), Colour::Red.dimmed()),
                LogLevel::Warn => (Colour::Yellow.normal(), Colour::Yellow.dimmed()),
                LogLevel::Info => (Colour::Blue.normal(), Colour::Blue.dimmed()),
                LogLevel::Debug => (Colour::Purple.normal(), Colour::Purple.dimmed()),
                LogLevel::Trace => (Colour::White.dimmed(), Colour::Black.normal()),
            };

            let strings = &[back.paint("["),
                            front.paint(format!("{}", record.level())),
                            back.paint("]"),
                            normal.paint(" "),
                            back.paint("["),
                            front.paint(record.location().module_path()),
                            back.paint("]"),
                            normal.paint(" "),
                            back.paint(format!("{}", record.args()))];

            format!("{}", ANSIStrings(strings))
        } else {
            format!("[{}] [{}] {}",
                    record.level(),
                    record.location().module_path(),
                    record.args())
        }
    };

    let mut builder = env_logger::LogBuilder::new();

    let filter = if quiet {
        LogLevelFilter::Off
    } else if let Some(l) = level {
        LogLevelFilter::from_str(l).unwrap_or(LogLevelFilter::Info)
    } else {
        LogLevelFilter::Info
    };

    builder.format(format).filter(None, filter);

    if let Ok(spec) = env::var("RUST_LOG") {
        builder.parse(&spec);
    }

    builder.init().unwrap();
}

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

    fn parse_args(args: &[&str]) -> Args {
        let a = Args::docopt().argv(args).decode().unwrap();
        println!("{:?}", a);
        a
    }

    #[test]
    fn test_docopt_kitchen_sink() {
        let a = parse_args(&["rq", "-l", "info", "-jP", ".foo.Bar", "select x"]);
        assert!(a.flag_input_json);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
        assert_eq!(a.flag_log, Some("info".to_owned()));
        assert_eq!(a.arg_query, "select x");
    }

    #[test]
    fn test_docopt_no_args() {
        parse_args(&["rq"]);
    }

    #[test]
    #[should_panic(expected = "Help")]
    fn test_docopt_help() {
        parse_args(&["rq", "--help"]);
    }

    #[test]
    fn test_docopt_version() {
        let a = parse_args(&["rq", "--version"]);
        assert!(a.flag_version);
    }

    #[test]
    fn test_docopt_input_json() {
        let a = parse_args(&["rq", "-j"]);
        assert!(a.flag_input_json);
    }

    #[test]
    fn test_docopt_input_json_long() {
        let a = parse_args(&["rq", "--input-json"]);
        assert!(a.flag_input_json);
    }

    #[test]
    fn test_docopt_output_json() {
        let a = parse_args(&["rq", "-J"]);
        assert!(a.flag_output_json);
    }

    #[test]
    fn test_docopt_output_json_long() {
        let a = parse_args(&["rq", "--output-json"]);
        assert!(a.flag_output_json);
    }

    #[test]
    fn test_docopt_input_cbor() {
        let a = parse_args(&["rq", "-c"]);
        assert!(a.flag_input_cbor);
    }

    #[test]
    fn test_docopt_input_cbor_long() {
        let a = parse_args(&["rq", "--input-cbor"]);
        assert!(a.flag_input_cbor);
    }

    #[test]
    fn test_docopt_output_cbor() {
        let a = parse_args(&["rq", "-C"]);
        assert!(a.flag_output_cbor);
    }

    #[test]
    fn test_docopt_output_cbor_long() {
        let a = parse_args(&["rq", "--output-cbor"]);
        assert!(a.flag_output_cbor);
    }

    #[test]
    fn test_docopt_input_protobuf() {
        let a = parse_args(&["rq", "-p", ".foo.Bar"]);
        assert_eq!(a.flag_input_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_input_protobuf_long() {
        let a = parse_args(&["rq", "--input-protobuf", ".foo.Bar"]);
        assert_eq!(a.flag_input_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_output_protobuf() {
        let a = parse_args(&["rq", "-P", ".foo.Bar"]);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    fn test_docopt_output_protobuf_long() {
        let a = parse_args(&["rq", "--output-protobuf", ".foo.Bar"]);
        assert_eq!(a.flag_output_protobuf, Some(".foo.Bar".to_owned()));
    }

    #[test]
    #[should_panic(expected = "NoMatch")]
    fn test_docopt_input_conflict() {
        parse_args(&["rq", "-jc"]);
    }

    #[test]
    #[should_panic(expected = "NoMatch")]
    fn test_docopt_output_conflict() {
        parse_args(&["rq", "-JC"]);
    }

    #[test]
    fn test_docopt_protobuf_add_schema() {
        let a = parse_args(&["rq", "-l", "info", "protobuf", "add", "schema.proto"]);
        assert_eq!(a.flag_log, Some("info".to_owned()));
        assert!(a.cmd_protobuf);
        assert!(a.cmd_add);
        assert_eq!(a.arg_schema, "schema.proto");
    }
}
<|endoftext|>


<commit_before>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, Tag, Language};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.hb_buffer, lang.0) }
    }

    fn get_language(&self) -> Language {
        Language(unsafe { hb::hb_buffer_get_language(self.hb_buffer) })
    }

    fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.hb_buffer, script) }
    }

    fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.hb_buffer) }
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe {
            hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32)
        }
    }
}

impl Clone for BufferRaw {
    fn clone(&self) -> Self {
        unsafe {
            hb::hb_buffer_reference(self.hb_buffer);
        }
        BufferRaw { hb_buffer: self.hb_buffer }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
#[derive(Clone)]
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        let mut result = String::with_capacity(self.len());
        for info in self.0.get_glyph_infos() {
            let chr = std::char::from_u32(info.codepoint).unwrap();
            result.push(chr)
        }
        result
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0.set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    pub fn get_language(&self) -> Language {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
#[derive(Clone)]
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("glyph positions", &self.get_glyph_positions())
            .field("glyph infos", &self.get_glyph_infos())
            .finish()
    }
}

#[derive(Debug, Clone)]
pub enum Buffer {
    UnicodeBuffer(UnicodeBuffer),
    GlyphBuffer(GlyphBuffer),
}
<commit_msg>Fix mutability issue in buffer.rs<commit_after>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, Tag, Language};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.hb_buffer, lang.0) }
    }

    fn get_language(&self) -> Language {
        Language(unsafe { hb::hb_buffer_get_language(self.hb_buffer) })
    }

    fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.hb_buffer, script) }
    }

    fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.hb_buffer) }
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &[GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &[GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe { hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32) }
    }
}

impl Clone for BufferRaw {
    fn clone(&self) -> Self {
        unsafe {
            hb::hb_buffer_reference(self.hb_buffer);
        }
        BufferRaw { hb_buffer: self.hb_buffer }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
#[derive(Clone)]
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        self.0
            .get_glyph_infos()
            .iter()
            .map(|info| std::char::from_u32(info.codepoint).unwrap())
            .collect()
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0.set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    pub fn get_language(&self) -> Language {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
#[derive(Clone)]
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &[GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &[GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("glyph positions", &self.get_glyph_positions())
            .field("glyph infos", &self.get_glyph_infos())
            .finish()
    }
}

#[derive(Debug, Clone)]
pub enum Buffer {
    UnicodeBuffer(UnicodeBuffer),
    GlyphBuffer(GlyphBuffer),
}
<|endoftext|>


<commit_before>use amq_protocol::frame::{BackToTheBuffer, GenError, GenResult, WriteContext};
use std::{
    cmp,
    io::{self, IoSlice, IoSliceMut},
};

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Buffer {
    memory: Vec<u8>,
    capacity: usize,
    position: usize,
    end: usize,
    available_data: usize,
}

// The bool is true when the checkpoint is to go backwards, false for forward
pub(crate) struct Checkpoint(usize, bool);

impl Buffer {
    pub(crate) fn with_capacity(capacity: usize) -> Buffer {
        Buffer {
            memory: vec![0; capacity],
            capacity,
            position: 0,
            end: 0,
            available_data: 0,
        }
    }

    pub(crate) fn checkpoint(&self) -> Checkpoint {
        Checkpoint(self.end, true)
    }

    pub(crate) fn rollback(&mut self, checkpoint: Checkpoint) {
        if checkpoint.1 {
            if self.end > checkpoint.0 {
                self.available_data -= self.end - checkpoint.0;
            } else {
                self.available_data -= self.end + (self.capacity - checkpoint.0);
            }
        } else {
            if self.end > checkpoint.0 {
                self.available_data += (self.capacity - self.end) + checkpoint.0;
            } else {
                self.available_data += checkpoint.0 - self.end;
            }
        }
        self.end = checkpoint.0;
    }

    pub(crate) fn grow(&mut self, new_size: usize) -> bool {
        if self.capacity >= new_size {
            return false;
        }

        let old_capacity = self.capacity;

        self.memory.resize(new_size, 0);
        self.capacity = new_size;

        if self.end < self.position {
            // FIXME: make sure there's enough room
            let (old, new) = self.memory.split_at_mut(old_capacity);
            new[..].copy_from_slice(&old[..self.end]);
            self.end += old_capacity;
        }

        true
    }

    pub(crate) fn available_data(&self) -> usize {
        self.available_data
    }

    fn available_space(&self) -> usize {
        self.capacity - self.available_data
    }

    pub(crate) fn consume(&mut self, count: usize, ring: bool) -> usize {
        let cnt = cmp::min(count, self.available_data());
        self.position += cnt;
        if ring {
            self.position %= self.capacity;
        }
        self.available_data -= cnt;
        cnt
    }

    pub(crate) fn fill(&mut self, count: usize, ring: bool) -> usize {
        let cnt = cmp::min(count, self.available_space());
        self.end += cnt;
        if ring {
            self.end %= self.capacity;
        }
        self.available_data += cnt;
        cnt
    }

    pub(crate) fn write_to<T: io::Write>(&self, writer: &mut T) -> io::Result<usize> {
        if self.available_data() == 0 {
            Ok(0)
        } else {
            if self.end > self.position {
                writer.write(&self.memory[self.position..self.end])
            } else {
                writer.write_vectored(&[
                    IoSlice::new(&self.memory[self.position..]),
                    IoSlice::new(&self.memory[..self.end]),
                ])
            }
        }
    }

    pub(crate) fn read_from<T: io::Read>(&mut self, reader: &mut T, ring: bool) -> io::Result<usize> {
        if self.available_space() == 0 {
            Ok(0)
        } else {
            if ring {
                if self.end >= self.position {
                    let (start, end) = self.memory.split_at_mut(self.end);
                    reader.read_vectored(
                        &mut [
                        IoSliceMut::new(&mut end[..]),
                        IoSliceMut::new(&mut start[..self.position]),
                        ][..],
                    )
                } else {
                    reader.read(&mut self.memory[self.end..self.position])
                }
            } else {
                reader.read(&mut self.memory[self.end..])
            }
        }
    }

    pub(crate) fn offset(&self, buf: &[u8]) -> usize {
        let bufptr = buf.as_ptr() as usize;
        if self.end >= self.position {
            let data = &self.memory[self.position..self.end];
            bufptr - data.as_ptr() as usize
        } else {
            let data = &self.memory[self.position..];
            let dataptr = data.as_ptr() as usize;
            if dataptr < bufptr {
                bufptr - dataptr
            } else {
                let data = &self.memory[..self.end];
                bufptr + self.capacity - self.position - data.as_ptr() as usize
            }
        }
    }

    pub(crate) fn data(&self) -> &[u8] {
        // FIXME: drop
        &self.memory[self.position..self.end]
    }

    pub(crate) fn shift(&mut self) {
        // FIXME: drop
        let length = self.end - self.position;
        if length > self.position {
            return;
        } else {
            let (start, end) = self.memory.split_at_mut(self.position);
            start[..length].copy_from_slice(&end[..length]);
        }
        self.position = 0;
        self.end = length;
    }

    pub(crate) fn shift_unless_available(&mut self, size: usize) {
        // FIXME: drop
        if self.available_space() < size {
            self.shift();
        }
    }
}

impl io::Write for &mut Buffer {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = if self.available_space() == 0 {
            0
        } else {
            if self.end >= self.position {
                let mut space = &mut self.memory[self.end..];
                let mut amt = space.write(data)?;
                if amt == self.capacity - self.end {
                    let mut space = &mut self.memory[..self.position];
                    amt += space.write(&data[amt..])?;
                }
                amt
            } else {
                let mut space = &mut self.memory[self.end..self.position];
                space.write(data)?
            }
        };
        self.fill(amt, true);
        Ok(amt)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl BackToTheBuffer for &mut Buffer {
    fn reserve_write_use<
        Tmp,
        Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
        Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
    >(
        s: WriteContext<Self>,
        reserved: usize,
        gen: &Gen,
        before: &Before,
    ) -> Result<WriteContext<Self>, GenError> {
        if s.write.available_space() < reserved {
            return Err(GenError::BufferTooSmall(
                reserved - s.write.available_space(),
            ));
        }
        let start = s.write.checkpoint();
        s.write.fill(reserved, true);
        gen(s).and_then(|(s, tmp)| {
            let mut end = s.write.checkpoint();
            end.1 = false;
            s.write.rollback(start);
            before(s, tmp).and_then(|s| {
                s.write.rollback(end);
                Ok(s)
            })
        })
    }
}
<commit_msg>rustfmt<commit_after>use amq_protocol::frame::{BackToTheBuffer, GenError, GenResult, WriteContext};
use std::{
    cmp,
    io::{self, IoSlice, IoSliceMut},
};

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Buffer {
    memory: Vec<u8>,
    capacity: usize,
    position: usize,
    end: usize,
    available_data: usize,
}

// The bool is true when the checkpoint is to go backwards, false for forward
pub(crate) struct Checkpoint(usize, bool);

impl Buffer {
    pub(crate) fn with_capacity(capacity: usize) -> Buffer {
        Buffer {
            memory: vec![0; capacity],
            capacity,
            position: 0,
            end: 0,
            available_data: 0,
        }
    }

    pub(crate) fn checkpoint(&self) -> Checkpoint {
        Checkpoint(self.end, true)
    }

    pub(crate) fn rollback(&mut self, checkpoint: Checkpoint) {
        if checkpoint.1 {
            if self.end > checkpoint.0 {
                self.available_data -= self.end - checkpoint.0;
            } else {
                self.available_data -= self.end + (self.capacity - checkpoint.0);
            }
        } else {
            if self.end > checkpoint.0 {
                self.available_data += (self.capacity - self.end) + checkpoint.0;
            } else {
                self.available_data += checkpoint.0 - self.end;
            }
        }
        self.end = checkpoint.0;
    }

    pub(crate) fn grow(&mut self, new_size: usize) -> bool {
        if self.capacity >= new_size {
            return false;
        }

        let old_capacity = self.capacity;

        self.memory.resize(new_size, 0);
        self.capacity = new_size;

        if self.end < self.position {
            // FIXME: make sure there's enough room
            let (old, new) = self.memory.split_at_mut(old_capacity);
            new[..].copy_from_slice(&old[..self.end]);
            self.end += old_capacity;
        }

        true
    }

    pub(crate) fn available_data(&self) -> usize {
        self.available_data
    }

    fn available_space(&self) -> usize {
        self.capacity - self.available_data
    }

    pub(crate) fn consume(&mut self, count: usize, ring: bool) -> usize {
        let cnt = cmp::min(count, self.available_data());
        self.position += cnt;
        if ring {
            self.position %= self.capacity;
        }
        self.available_data -= cnt;
        cnt
    }

    pub(crate) fn fill(&mut self, count: usize, ring: bool) -> usize {
        let cnt = cmp::min(count, self.available_space());
        self.end += cnt;
        if ring {
            self.end %= self.capacity;
        }
        self.available_data += cnt;
        cnt
    }

    pub(crate) fn write_to<T: io::Write>(&self, writer: &mut T) -> io::Result<usize> {
        if self.available_data() == 0 {
            Ok(0)
        } else {
            if self.end > self.position {
                writer.write(&self.memory[self.position..self.end])
            } else {
                writer.write_vectored(&[
                    IoSlice::new(&self.memory[self.position..]),
                    IoSlice::new(&self.memory[..self.end]),
                ])
            }
        }
    }

    pub(crate) fn read_from<T: io::Read>(
        &mut self,
        reader: &mut T,
        ring: bool,
    ) -> io::Result<usize> {
        if self.available_space() == 0 {
            Ok(0)
        } else {
            if ring {
                if self.end >= self.position {
                    let (start, end) = self.memory.split_at_mut(self.end);
                    reader.read_vectored(
                        &mut [
                            IoSliceMut::new(&mut end[..]),
                            IoSliceMut::new(&mut start[..self.position]),
                        ][..],
                    )
                } else {
                    reader.read(&mut self.memory[self.end..self.position])
                }
            } else {
                reader.read(&mut self.memory[self.end..])
            }
        }
    }

    pub(crate) fn offset(&self, buf: &[u8]) -> usize {
        let bufptr = buf.as_ptr() as usize;
        if self.end >= self.position {
            let data = &self.memory[self.position..self.end];
            bufptr - data.as_ptr() as usize
        } else {
            let data = &self.memory[self.position..];
            let dataptr = data.as_ptr() as usize;
            if dataptr < bufptr {
                bufptr - dataptr
            } else {
                let data = &self.memory[..self.end];
                bufptr + self.capacity - self.position - data.as_ptr() as usize
            }
        }
    }

    pub(crate) fn data(&self) -> &[u8] {
        // FIXME: drop
        &self.memory[self.position..self.end]
    }

    pub(crate) fn shift(&mut self) {
        // FIXME: drop
        let length = self.end - self.position;
        if length > self.position {
            return;
        } else {
            let (start, end) = self.memory.split_at_mut(self.position);
            start[..length].copy_from_slice(&end[..length]);
        }
        self.position = 0;
        self.end = length;
    }

    pub(crate) fn shift_unless_available(&mut self, size: usize) {
        // FIXME: drop
        if self.available_space() < size {
            self.shift();
        }
    }
}

impl io::Write for &mut Buffer {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = if self.available_space() == 0 {
            0
        } else {
            if self.end >= self.position {
                let mut space = &mut self.memory[self.end..];
                let mut amt = space.write(data)?;
                if amt == self.capacity - self.end {
                    let mut space = &mut self.memory[..self.position];
                    amt += space.write(&data[amt..])?;
                }
                amt
            } else {
                let mut space = &mut self.memory[self.end..self.position];
                space.write(data)?
            }
        };
        self.fill(amt, true);
        Ok(amt)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl BackToTheBuffer for &mut Buffer {
    fn reserve_write_use<
        Tmp,
        Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
        Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
    >(
        s: WriteContext<Self>,
        reserved: usize,
        gen: &Gen,
        before: &Before,
    ) -> Result<WriteContext<Self>, GenError> {
        if s.write.available_space() < reserved {
            return Err(GenError::BufferTooSmall(
                reserved - s.write.available_space(),
            ));
        }
        let start = s.write.checkpoint();
        s.write.fill(reserved, true);
        gen(s).and_then(|(s, tmp)| {
            let mut end = s.write.checkpoint();
            end.1 = false;
            s.write.rollback(start);
            before(s, tmp).and_then(|s| {
                s.write.rollback(end);
                Ok(s)
            })
        })
    }
}
<|endoftext|>