<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

use crate::error::IDLError;
use crate::module::Module;
use crate::package::Package;
use crate::pretty_writer::PrettyWriter;
use crate::types::{
    AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named,
    StructDataType,
};
use std::io::prelude::*;

/// Generator for the C backend
pub struct CGenerator {
    pub w: PrettyWriter,
}

impl CGenerator {
    pub fn new(w: Box<dyn Write>) -> Self {
        let mut w = PrettyWriter::new(w);
        let prelude = r"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>";
        for line in prelude.lines() {
            w.write_line(line.as_ref()).unwrap();
        }
        w.eob().unwrap();
        Self { w }
    }

    pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> {
        for (_ident, module) in package.modules.iter() {
            for ref dt in module.datatypes() {
                self.gen_type_header(module, dt)?;
                match &dt.entity.variant {
                    DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?,
                    DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?,
                    DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?,
                }
            }
            for fdecl in module.func_decls() {
                self.gen_function(module, &fdecl)?;
            }
        }
        Ok(())
    }

    fn gen_type_header(&mut self, _module: &Module, dt: &Named<DataType>) -> Result<(), IDLError> {
        self.w
            .eob()?
            .writeln(format!("// ---------- {} ----------", dt.name.name))?
            .eob()?;
        Ok(())
    }

    // The most important thing in alias generation is to cache the size
    // and alignment rules of what it ultimately points to
    fn gen_alias(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        alias: &AliasDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        self.w.writeln(format!(
            "typedef {} {};",
            self.type_ref_name(module, &alias.to),
            dtname
        ))?;
        self.w.eob()?;

        // Add an assertion to check that resolved size is the one we computed
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");",
            dtname, dt.entity.repr_size
        ))?;
        self.w.eob()?;

        Ok(())
    }

    fn gen_struct(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        struct_: &StructDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        self.w.writeln(format!("{} {{", dtname))?;
        let mut w_block = self.w.new_block();
        for member in struct_.members.iter() {
            w_block.writeln(format!(
                "{} {};",
                self.type_ref_name(module, &member.type_),
                member.name
            ))?;
        }
        self.w.writeln("};")?;
        self.w.eob()?;

        // Skip the first member, as it will always be at the beginning of the structure
        for (i, member) in struct_.members.iter().enumerate().skip(1) {
            self.w.writeln(format!(
                "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");",
                dtname, member.name, member.offset
            ))?;
        }

        let struct_size = dt.entity.repr_size;
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");",
            dtname, struct_size,
        ))?;
        self.w.eob()?;

        Ok(())
    }

    // Enums generate both a specific typedef, and a traditional C-style enum
    // The typedef is required to use a native type which is consistent across all architectures
    fn gen_enum(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        enum_: &EnumDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        let type_size = dt.entity.repr_size;
        self.w.writeln(format!("{} {{", dtname))?;
        let mut pretty_writer_i1 = self.w.new_block();
        for (i, named_member) in enum_.members.iter().enumerate() {
            pretty_writer_i1.writeln(format!(
                "{}, // {}",
                macro_for(&dt.name.name, &named_member.name),
                i
            ))?;
        }
        self.w.writeln("};")?;
        self.w.eob()?;
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");",
            dtname, type_size
        ))?;
        self.w.eob()?;
        Ok(())
    }

    fn gen_function(
        &mut self,
        _module: &Module,
        _func_decl_entry: &Named<FuncDecl>,
    ) -> Result<(), IDLError> {
        // UNIMPLEMENTED!!
        Ok(())
    }

    // Return `true` if the type is an atom, an emum, or an alias to one of these
    pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool {
        let inner_type = match type_ {
            DataTypeRef::Atom(_) => return true,
            DataTypeRef::Defined(inner_type) => inner_type,
        };
        let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype");
        match inner_data_type_entry.entity.variant {
            DataTypeVariant::Struct { .. } => false,
            DataTypeVariant::Enum { .. } => true,
            DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to),
        }
    }

    /// Return the type refererence, with aliases being resolved
    pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef {
        let inner_type = match type_ {
            DataTypeRef::Atom(_) => return type_,
            DataTypeRef::Defined(inner_type) => inner_type,
        };
        let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype");
        if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant {
            self.unalias(module, &a.to)
        } else {
            type_
        }
    }

    fn type_name(&self, dt: &Named<DataType>) -> String {
        match dt.entity.variant {
            DataTypeVariant::Struct(_) => format!("struct {}", dt.name.name),
            DataTypeVariant::Enum(_) => format!("enum {}", dt.name.name),
            DataTypeVariant::Alias(_) => format!("{}", dt.name.name),
        }
    }

    fn type_ref_name(&self, module: &Module, type_: &DataTypeRef) -> String {
        match type_ {
            DataTypeRef::Atom(a) => atom_type_name(a).to_owned(),
            DataTypeRef::Defined(id) => {
                let dt = &module.get_datatype(*id).expect("type_name of valid ref");
                self.type_name(dt)
            }
        }
    }
}

fn atom_type_name(atom_type: &AtomType) -> &'static str {
    match atom_type {
        AtomType::Bool => "bool",
        AtomType::U8 => "uint8_t",
        AtomType::U16 => "uint16_t",
        AtomType::U32 => "uint32_t",
        AtomType::U64 => "uint64_t",
        AtomType::I8 => "int8_t",
        AtomType::I16 => "int16_t",
        AtomType::I32 => "int32_t",
        AtomType::I64 => "int64_t",
        AtomType::F32 => "float",
        AtomType::F64 => "double",
    }
}

fn macro_for(prefix: &str, name: &str) -> String {
    let mut macro_name = String::new();
    macro_name.push_str(&prefix.to_uppercase());
    macro_name.push('_');
    let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase();
    for c in name.chars() {
        let is_uppercase = c.is_uppercase();
        if is_uppercase != previous_was_uppercase {
            macro_name.push('_');
        }
        for uc in c.to_uppercase() {
            macro_name.push(uc);
        }
        previous_was_uppercase = is_uppercase;
    }
    macro_name
}
<commit_msg>lucet-idl: C backend emits abi-level func decl<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]

use crate::error::IDLError;
use crate::module::Module;
use crate::package::Package;
use crate::pretty_writer::PrettyWriter;
use crate::types::{
    AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType,
    FuncDecl, Named, StructDataType,
};
use std::io::prelude::*;

/// Generator for the C backend
pub struct CGenerator {
    pub w: PrettyWriter,
}

impl CGenerator {
    pub fn new(w: Box<dyn Write>) -> Self {
        let mut w = PrettyWriter::new(w);
        let prelude = r"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>";
        for line in prelude.lines() {
            w.write_line(line.as_ref()).unwrap();
        }
        w.eob().unwrap();
        Self { w }
    }

    pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> {
        for (_ident, module) in package.modules.iter() {
            for ref dt in module.datatypes() {
                self.gen_type_header(module, dt)?;
                match &dt.entity.variant {
                    DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?,
                    DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?,
                    DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?,
                }
            }
            for fdecl in module.func_decls() {
                self.gen_function(module, &fdecl)?;
            }
        }
        Ok(())
    }

    fn gen_type_header(&mut self, _module: &Module, dt: &Named<DataType>) -> Result<(), IDLError> {
        self.w
            .eob()?
            .writeln(format!("// ---------- {} ----------", dt.name.name))?
            .eob()?;
        Ok(())
    }

    // The most important thing in alias generation is to cache the size
    // and alignment rules of what it ultimately points to
    fn gen_alias(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        alias: &AliasDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        self.w.writeln(format!(
            "typedef {} {};",
            self.type_ref_name(module, &alias.to),
            dtname
        ))?;
        self.w.eob()?;

        // Add an assertion to check that resolved size is the one we computed
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");",
            dtname, dt.entity.repr_size
        ))?;
        self.w.eob()?;

        Ok(())
    }

    fn gen_struct(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        struct_: &StructDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        self.w.writeln(format!("{} {{", dtname))?;
        let mut w_block = self.w.new_block();
        for member in struct_.members.iter() {
            w_block.writeln(format!(
                "{} {};",
                self.type_ref_name(module, &member.type_),
                member.name
            ))?;
        }
        self.w.writeln("};")?;
        self.w.eob()?;

        // Skip the first member, as it will always be at the beginning of the structure
        for (i, member) in struct_.members.iter().enumerate().skip(1) {
            self.w.writeln(format!(
                "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");",
                dtname, member.name, member.offset
            ))?;
        }

        let struct_size = dt.entity.repr_size;
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");",
            dtname, struct_size,
        ))?;
        self.w.eob()?;

        Ok(())
    }

    // Enums generate both a specific typedef, and a traditional C-style enum
    // The typedef is required to use a native type which is consistent across all architectures
    fn gen_enum(
        &mut self,
        module: &Module,
        dt: &Named<DataType>,
        enum_: &EnumDataType,
    ) -> Result<(), IDLError> {
        let dtname = self.type_name(dt);
        let type_size = dt.entity.repr_size;
        self.w.writeln(format!("{} {{", dtname))?;
        let mut pretty_writer_i1 = self.w.new_block();
        for (i, named_member) in enum_.members.iter().enumerate() {
            pretty_writer_i1.writeln(format!(
                "{}, // {}",
                macro_for(&dt.name.name, &named_member.name),
                i
            ))?;
        }
        self.w.writeln("};")?;
        self.w.eob()?;
        self.w.writeln(format!(
            "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");",
            dtname, type_size
        ))?;
        self.w.eob()?;
        Ok(())
    }

    /// Currently support generating ABI level definition for C guests. Bindings not supported.
    fn gen_function(&mut self, _module: &Module, func: &Named<FuncDecl>) -> Result<(), IDLError> {
        let func = func.entity;

        let return_decl = match func.rets.len() {
            0 => "void",
            1 => abi_type_name(&func.rets[0].type_),
            _ => unreachable!("functions limited to 0 or 1 return arguments"),
        };

        let arg_list = func
            .args
            .iter()
            .map(|a| format!("{} {}", abi_type_name(&a.type_), a.name))
            .collect::<Vec<String>>()
            .join(",");

        self.w.writeln(format!(
            "extern {} {}({});",
            return_decl, func.binding_name, arg_list,
        ))?;

        Ok(())
    }

    // Return `true` if the type is an atom, an emum, or an alias to one of these
    pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool {
        let inner_type = match type_ {
            DataTypeRef::Atom(_) => return true,
            DataTypeRef::Defined(inner_type) => inner_type,
        };
        let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype");
        match inner_data_type_entry.entity.variant {
            DataTypeVariant::Struct { .. } => false,
            DataTypeVariant::Enum { .. } => true,
            DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to),
        }
    }

    /// Return the type refererence, with aliases being resolved
    pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef {
        let inner_type = match type_ {
            DataTypeRef::Atom(_) => return type_,
            DataTypeRef::Defined(inner_type) => inner_type,
        };
        let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype");
        if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant {
            self.unalias(module, &a.to)
        } else {
            type_
        }
    }

    fn type_name(&self, dt: &Named<DataType>) -> String {
        match dt.entity.variant {
            DataTypeVariant::Struct(_) => format!("struct {}", dt.name.name),
            DataTypeVariant::Enum(_) => format!("enum {}", dt.name.name),
            DataTypeVariant::Alias(_) => format!("{}", dt.name.name),
        }
    }

    fn type_ref_name(&self, module: &Module, type_: &DataTypeRef) -> String {
        match type_ {
            DataTypeRef::Atom(a) => atom_type_name(a).to_owned(),
            DataTypeRef::Defined(id) => {
                let dt = &module.get_datatype(*id).expect("type_name of valid ref");
                self.type_name(dt)
            }
        }
    }
}

fn abi_type_name(abi_type: &AbiType) -> &'static str {
    match abi_type {
        AbiType::I32 => atom_type_name(&AtomType::I32),
        AbiType::I64 => atom_type_name(&AtomType::I64),
        AbiType::F32 => atom_type_name(&AtomType::F32),
        AbiType::F64 => atom_type_name(&AtomType::F64),
    }
}

fn atom_type_name(atom_type: &AtomType) -> &'static str {
    match atom_type {
        AtomType::Bool => "bool",
        AtomType::U8 => "uint8_t",
        AtomType::U16 => "uint16_t",
        AtomType::U32 => "uint32_t",
        AtomType::U64 => "uint64_t",
        AtomType::I8 => "int8_t",
        AtomType::I16 => "int16_t",
        AtomType::I32 => "int32_t",
        AtomType::I64 => "int64_t",
        AtomType::F32 => "float",
        AtomType::F64 => "double",
    }
}

fn macro_for(prefix: &str, name: &str) -> String {
    let mut macro_name = String::new();
    macro_name.push_str(&prefix.to_uppercase());
    macro_name.push('_');
    let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase();
    for c in name.chars() {
        let is_uppercase = c.is_uppercase();
        if is_uppercase != previous_was_uppercase {
            macro_name.push('_');
        }
        for uc in c.to_uppercase() {
            macro_name.push(uc);
        }
        previous_was_uppercase = is_uppercase;
    }
    macro_name
}
<|endoftext|>


<commit_before>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        for cache_entry in self.line_cache.iter_mut() {
            if cache_entry.line.contains(&pos) {
                cache_entry.time_stamp = self.time_stamp;

                return Some((
                    cache_entry.file.clone(),
                    cache_entry.line_number,
                    pos - cache_entry.line.start,
                ));
            }
        }

        // No cache hit ...
        let mut oldest = 0;
        for index in 1..self.line_cache.len() {
            if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = index;
            }
        }

        let cache_entry = &mut self.line_cache[oldest];

        // If the entry doesn't point to the correct file, fix it up
        if !file_contains(&cache_entry.file, pos) {
            let file_valid;
            if self.source_map.files().len() > 0 {
                let file_index = self.source_map.lookup_source_file_idx(pos);
                let file = self.source_map.files()[file_index].clone();

                if file_contains(&file, pos) {
                    cache_entry.file = file;
                    cache_entry.file_index = file_index;
                    file_valid = true;
                } else {
                    file_valid = false;
                }
            } else {
                file_valid = false;
            }

            if !file_valid {
                return None;
            }
        }

        let line_index = cache_entry.file.lookup_line(pos).unwrap();
        let line_bounds = cache_entry.file.line_bounds(line_index);

        cache_entry.line_number = line_index + 1;
        cache_entry.line = line_bounds;
        cache_entry.time_stamp = self.time_stamp;

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<commit_msg>rustc_span: avoid unnecessary cloning in byte_pos_to_line_and_col<commit_after>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        for cache_entry in self.line_cache.iter_mut() {
            if cache_entry.line.contains(&pos) {
                cache_entry.time_stamp = self.time_stamp;

                return Some((
                    cache_entry.file.clone(),
                    cache_entry.line_number,
                    pos - cache_entry.line.start,
                ));
            }
        }

        // No cache hit ...
        let mut oldest = 0;
        for index in 1..self.line_cache.len() {
            if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = index;
            }
        }

        let cache_entry = &mut self.line_cache[oldest];

        // If the entry doesn't point to the correct file, fix it up
        if !file_contains(&cache_entry.file, pos) {
            let file_valid;
            if self.source_map.files().len() > 0 {
                let file_index = self.source_map.lookup_source_file_idx(pos);
                let file = &self.source_map.files()[file_index];

                if file_contains(&file, pos) {
                    cache_entry.file = file.clone();
                    cache_entry.file_index = file_index;
                    file_valid = true;
                } else {
                    file_valid = false;
                }
            } else {
                file_valid = false;
            }

            if !file_valid {
                return None;
            }
        }

        let line_index = cache_entry.file.lookup_line(pos).unwrap();
        let line_bounds = cache_entry.file.line_bounds(line_index);

        cache_entry.line_number = line_index + 1;
        cache_entry.line = line_bounds;
        cache_entry.time_stamp = self.time_stamp;

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<|endoftext|>


<commit_before>use super::internal::*;
use super::*;
use std::usize;
use std::cmp;

/// `Interleave` is an iterator that interleaves elements of iterators
/// `i` and `j` in one continuous iterator. This struct is created by
/// the [`interleave()`] method on [`IndexedParallelIterator`]
///
/// [`interleave()`]: trait.IndexedParallelIterator.html#method.interleave
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    i: I,
    j: J,
}

/// Create a new `Interleave` iterator
///
/// NB: a free fn because it is NOT part of the end-user API.
pub fn new<I, J>(i: I, j: J) -> Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    Interleave { i: i, j: j }
}

impl<I, J> ParallelIterator for Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    type Item = I::Item;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: Consumer<I::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<I, J> IndexedParallelIterator for Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>,
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn len(&mut self) -> usize {
        self.i.len() + self.j.len()
    }

    fn with_producer<CB>(mut self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        let (i_len, j_len) = (self.i.len(), self.j.len());
        return self.i.with_producer(CallbackI {
            callback: callback,
            i_len: i_len,
            j_len: j_len,
            flag: false,
            j: self.j
        });

        struct CallbackI<CB, J> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            flag: bool,
            j: J
        }

        impl<CB, J> ProducerCallback<J::Item> for CallbackI<CB, J>
            where J: IndexedParallelIterator,
                  CB: ProducerCallback<J::Item>
        {
            type Output = CB::Output;

            fn callback<I>(self, i_producer: I) -> Self::Output
                where I: Producer<Item = J::Item>
            {
                self.j.with_producer(CallbackJ {
                    i_producer: i_producer,
                    i_len: self.i_len,
                    j_len: self.j_len,
                    flag: self.flag,
                    callback: self.callback
                })
            }
        }

        struct CallbackJ<CB, I> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            flag: bool,
            i_producer: I
        }

        impl<CB, I> ProducerCallback<I::Item> for CallbackJ<CB, I>
            where I: Producer,
                  CB: ProducerCallback<I::Item>
        {
            type Output = CB::Output;

            fn callback<J>(self, j_producer: J) -> Self::Output
                where J: Producer<Item = I::Item>
            {
                let producer = InterleaveProducer::new(self.i_producer, j_producer, self.i_len, self.j_len, self.flag);
                self.callback.callback(producer)
            }
        }
    }
}

pub struct InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    i: I,
    j: J,
    i_len: usize,
    j_len: usize,
    flag: bool,
}

impl<I, J> InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    fn new(i: I, j: J, i_len: usize, j_len: usize, flag: bool) -> InterleaveProducer<I, J> {
        InterleaveProducer { i: i, j: j, i_len: i_len, j_len: j_len, flag: flag }
    }
}

impl<I, J> Producer for InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    type Item = I::Item;
    type IntoIter = InterleaveSeq<I::IntoIter, J::IntoIter>;

    fn into_iter(self) -> Self::IntoIter {
        InterleaveSeq {
            i: self.i.into_iter(),
            j: self.j.into_iter(),
            flag: self.flag,
        }
    }

    fn min_len(&self) -> usize {
        cmp::max(self.i.min_len(), self.j.min_len())
    }

    fn max_len(&self) -> usize {
        cmp::min(self.i.max_len(), self.j.max_len())
    }

    /// We know 0 < index <= self.i_len + self.j_len
    ///
    /// Find a, b satisfying:
    ///
    ///  (1) 0 < a <= self.i_len
    ///  (2) 0 < b <= self.j_len
    ///  (3) a + b == index
    ///
    /// For even splits, set a = b = index/2.
    /// For odd splits, set a = (index/2)+1, b = index/2, if `i`
    /// should yield the next element, otherwise, if `j` should yield
    /// the next element, set a = index/2 and b = (index/2)+1
    fn split_at(self, index: usize) -> (Self, Self) {
        let even = index%2 == 0;
        let idx = index >> 1;

        let odd_offset = |flag| if flag { 0 } else { 1 };

        // desired split
        let (i_idx, j_idx) = (idx + odd_offset(even || self.flag),
                              idx + odd_offset(even || !self.flag));

        let (i_split, j_split) = if self.i_len >= i_idx && self.j_len >= j_idx {
            (i_idx, j_idx)
        } else if self.i_len >= i_idx {
            // j too short
            (index - self.j_len, self.j_len)
        } else {
            // i too short
            (self.i_len, index - self.i_len)
        };

        let trailing_flag = even == self.flag;
        let (i_left, i_right) = self.i.split_at(i_split);
        let (j_left, j_right) = self.j.split_at(j_split);

        (InterleaveProducer::new(
            i_left,
            j_left,
            i_split,
            j_split,
            self.flag
        ), InterleaveProducer::new(
            i_right,
            j_right,
            self.i_len - i_split,
            self.j_len - j_split,
            trailing_flag
        ))
    }
}

/// Wrapper for Interleave to implement DoubleEndedIterator and
/// ExactSizeIterator.
pub struct InterleaveSeq<I, J> {
    i: I,
    j: J,

    /// Flag to control which iterator should provide the next
    /// element. If `false` then `i` produces the next element, when
    /// `true` then the next element should be from `j`.
    flag: bool
}

/// Iterator implementation for InterleaveSeq. This implementation is
/// taken more or less verbatim from itertools. It is replicated here
/// (instead of calling itertools directly), because we also need to
/// implement `DoubledEndedIterator` and `ExactSizeIterator`.
impl<I, J> Iterator for InterleaveSeq<I, J>
    where I: Iterator,
          J: Iterator<Item = I::Item>
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.flag = !self.flag;
        if self.flag {
            match self.i.next() {
                None => self.j.next(),
                r => r
            }
        } else {
            match self.j.next() {
                None => self.i.next(),
                r => r
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (ih, jh) = (self.i.size_hint(), self.j.size_hint());
        let min = ih.0.saturating_add(jh.0);
        let max = match (ih.1, jh.1) {
            (Some(x), Some(y)) => x.checked_add(y),
            _=> None
        };
        (min, max)
    }
}

// The implementation for DoubleEndedIterator requires
// ExactSizeIterator to provide `next_back()`. The last element will
// come from the iterator that runs out last (ie has the most elements
// in it). If the iterators have the same number of elements, then the
// last iterator will provide the last element.
impl<I, J> DoubleEndedIterator for InterleaveSeq<I, J>
    where I: DoubleEndedIterator + ExactSizeIterator,
          J: DoubleEndedIterator<Item = I::Item> + ExactSizeIterator<Item = I::Item>
{
    #[inline]
    fn next_back(&mut self) -> Option<I::Item> {
        if self.i.len() == self.j.len() {
            if self.flag {
                self.i.next_back()
            } else {
                self.j.next_back()
            }
        } else if self.i.len() < self.j.len() {
            self.j.next_back()
        } else {
            self.i.next_back()
        }
    }
}

impl<I, J> ExactSizeIterator for InterleaveSeq<I, J>
    where I: ExactSizeIterator,
          J: ExactSizeIterator<Item = I::Item>
{
    #[inline]
    fn len(&self) -> usize {
        self.i.len() + self.j.len()
    }
}
<commit_msg>interleave: Review changes<commit_after>use super::internal::*;
use super::*;
use std::usize;
use std::cmp;
use std::iter::Fuse;

/// `Interleave` is an iterator that interleaves elements of iterators
/// `i` and `j` in one continuous iterator. This struct is created by
/// the [`interleave()`] method on [`IndexedParallelIterator`]
///
/// [`interleave()`]: trait.IndexedParallelIterator.html#method.interleave
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    i: I,
    j: J,
}

/// Create a new `Interleave` iterator
///
/// NB: a free fn because it is NOT part of the end-user API.
pub fn new<I, J>(i: I, j: J) -> Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    Interleave { i: i, j: j }
}

impl<I, J> ParallelIterator for Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>
{
    type Item = I::Item;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: Consumer<I::Item>
    {
        bridge(self, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.len())
    }
}

impl<I, J> IndexedParallelIterator for Interleave<I, J>
    where I: IndexedParallelIterator,
          J: IndexedParallelIterator<Item = I::Item>,
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self, consumer)
    }

    fn len(&mut self) -> usize {
        self.i.len() + self.j.len()
    }

    fn with_producer<CB>(mut self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        let (i_len, j_len) = (self.i.len(), self.j.len());
        return self.i.with_producer(CallbackI {
            callback: callback,
            i_len: i_len,
            j_len: j_len,
            i_next: false,
            j: self.j
        });

        struct CallbackI<CB, J> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            i_next: bool,
            j: J
        }

        impl<CB, J> ProducerCallback<J::Item> for CallbackI<CB, J>
            where J: IndexedParallelIterator,
                  CB: ProducerCallback<J::Item>
        {
            type Output = CB::Output;

            fn callback<I>(self, i_producer: I) -> Self::Output
                where I: Producer<Item = J::Item>
            {
                self.j.with_producer(CallbackJ {
                    i_producer: i_producer,
                    i_len: self.i_len,
                    j_len: self.j_len,
                    i_next: self.i_next,
                    callback: self.callback
                })
            }
        }

        struct CallbackJ<CB, I> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            i_next: bool,
            i_producer: I
        }

        impl<CB, I> ProducerCallback<I::Item> for CallbackJ<CB, I>
            where I: Producer,
                  CB: ProducerCallback<I::Item>
        {
            type Output = CB::Output;

            fn callback<J>(self, j_producer: J) -> Self::Output
                where J: Producer<Item = I::Item>
            {
                let producer = InterleaveProducer::new(self.i_producer, j_producer, self.i_len, self.j_len, self.i_next);
                self.callback.callback(producer)
            }
        }
    }
}

pub struct InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    i: I,
    j: J,
    i_len: usize,
    j_len: usize,
    i_next: bool,
}

impl<I, J> InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    fn new(i: I, j: J, i_len: usize, j_len: usize, i_next: bool) -> InterleaveProducer<I, J> {
        InterleaveProducer { i: i, j: j, i_len: i_len, j_len: j_len, i_next: i_next }
    }
}

impl<I, J> Producer for InterleaveProducer<I, J>
    where I: Producer,
          J: Producer<Item = I::Item>
{
    type Item = I::Item;
    type IntoIter = InterleaveSeq<I::IntoIter, J::IntoIter>;

    fn into_iter(self) -> Self::IntoIter {
        InterleaveSeq {
            i: self.i.into_iter().fuse(),
            j: self.j.into_iter().fuse(),
            i_next: self.i_next,
        }
    }

    fn min_len(&self) -> usize {
        cmp::max(self.i.min_len(), self.j.min_len())
    }

    fn max_len(&self) -> usize {
        cmp::min(self.i.max_len(), self.j.max_len())
    }

    /// We know 0 < index <= self.i_len + self.j_len
    ///
    /// Find a, b satisfying:
    ///
    ///  (1) 0 < a <= self.i_len
    ///  (2) 0 < b <= self.j_len
    ///  (3) a + b == index
    ///
    /// For even splits, set a = b = index/2.
    /// For odd splits, set a = (index/2)+1, b = index/2, if `i`
    /// should yield the next element, otherwise, if `j` should yield
    /// the next element, set a = index/2 and b = (index/2)+1
    fn split_at(self, index: usize) -> (Self, Self) {
        let even = index%2 == 0;
        let idx = index >> 1;

        let odd_offset = |flag| if flag { 0 } else { 1 };

        // desired split
        let (i_idx, j_idx) = (idx + odd_offset(even || self.i_next),
                              idx + odd_offset(even || !self.i_next));

        let (i_split, j_split) = if self.i_len >= i_idx && self.j_len >= j_idx {
            (i_idx, j_idx)
        } else if self.i_len >= i_idx {
            // j too short
            (index - self.j_len, self.j_len)
        } else {
            // i too short
            (self.i_len, index - self.i_len)
        };

        let trailing_i_next = even == self.i_next;
        let (i_left, i_right) = self.i.split_at(i_split);
        let (j_left, j_right) = self.j.split_at(j_split);

        (InterleaveProducer::new(
            i_left,
            j_left,
            i_split,
            j_split,
            self.i_next
        ), InterleaveProducer::new(
            i_right,
            j_right,
            self.i_len - i_split,
            self.j_len - j_split,
            trailing_i_next
        ))
    }
}

/// Wrapper for Interleave to implement DoubleEndedIterator and
/// ExactSizeIterator.
///
/// This iterator is fused.
pub struct InterleaveSeq<I, J> {
    i: Fuse<I>,
    j: Fuse<J>,

    /// Flag to control which iterator should provide the next element. When
    /// `false` then `i` produces the next element, otherwise `j` produces the
    /// next element.
    i_next: bool
}

/// Iterator implementation for InterleaveSeq. This implementation is
/// taken more or less verbatim from itertools. It is replicated here
/// (instead of calling itertools directly), because we also need to
/// implement `DoubledEndedIterator` and `ExactSizeIterator`.
impl<I, J> Iterator for InterleaveSeq<I, J>
    where I: Iterator,
          J: Iterator<Item = I::Item>
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.i_next = !self.i_next;
        if self.i_next {
            match self.i.next() {
                None => self.j.next(),
                r => r
            }
        } else {
            match self.j.next() {
                None => self.i.next(),
                r => r
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (ih, jh) = (self.i.size_hint(), self.j.size_hint());
        let min = ih.0.saturating_add(jh.0);
        let max = match (ih.1, jh.1) {
            (Some(x), Some(y)) => x.checked_add(y),
            _=> None
        };
        (min, max)
    }
}

// The implementation for DoubleEndedIterator requires
// ExactSizeIterator to provide `next_back()`. The last element will
// come from the iterator that runs out last (ie has the most elements
// in it). If the iterators have the same number of elements, then the
// last iterator will provide the last element.
impl<I, J> DoubleEndedIterator for InterleaveSeq<I, J>
    where I: DoubleEndedIterator + ExactSizeIterator,
          J: DoubleEndedIterator<Item = I::Item> + ExactSizeIterator<Item = I::Item>
{
    #[inline]
    fn next_back(&mut self) -> Option<I::Item> {
        if self.i.len() == self.j.len() {
            if self.i_next {
                self.i.next_back()
            } else {
                self.j.next_back()
            }
        } else if self.i.len() < self.j.len() {
            self.j.next_back()
        } else {
            self.i.next_back()
        }
    }
}

impl<I, J> ExactSizeIterator for InterleaveSeq<I, J>
    where I: ExactSizeIterator,
          J: ExactSizeIterator<Item = I::Item>
{
    #[inline]
    fn len(&self) -> usize {
        self.i.len() + self.j.len()
    }
}
<|endoftext|>


<commit_before>mod download;
mod extract;
mod find_package;
mod verify;<commit_msg>Removed mod.rs<commit_after><|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

//!
//! The following tokens are present in the expr grammar:
//! * integer literal;
//! * string literal;
//! * infix binary operators;
//! * prefix operators.
//!
//! According to the man-page of expr we have expression split into tokens (each token -- separate CLI-argument).
//! Hence all we need is to map the strings into the Token structures, except for some ugly fiddling with +-escaping.
//!

#[derive(Debug, Clone)]
pub enum Token {
    Value {
        value: String,
    },

    ParOpen,
    ParClose,

    InfixOp {
        precedence: u8,
        left_assoc: bool,
        value: String,
    },

    PrefixOp {
        arity: usize,
        value: String,
    },
}
impl Token {
    fn new_infix_op(v: &str, left_assoc: bool, precedence: u8) -> Self {
        Token::InfixOp {
            left_assoc,
            precedence,
            value: v.into(),
        }
    }
    fn new_value(v: &str) -> Self {
        Token::Value { value: v.into() }
    }

    fn is_infix_plus(&self) -> bool {
        match *self {
            Token::InfixOp { ref value, .. } => value == "+",
            _ => false,
        }
    }
    fn is_a_number(&self) -> bool {
        match *self {
            Token::Value { ref value, .. } => match value.parse::<i64>() {
                Ok(_) => true,
                Err(_) => false,
            },
            _ => false,
        }
    }
    fn is_a_close_paren(&self) -> bool {
        match *self {
            Token::ParClose => true,
            _ => false,
        }
    }
}

pub fn strings_to_tokens(strings: &[String]) -> Result<Vec<(usize, Token)>, String> {
    let mut tokens_acc = Vec::with_capacity(strings.len());
    let mut tok_idx = 1;

    for s in strings {
        let token_if_not_escaped = match s.as_ref() {
            "(" => Token::ParOpen,
            ")" => Token::ParClose,

            "^" => Token::new_infix_op(&s, false, 7),

            ":" => Token::new_infix_op(&s, true, 6),

            "*" => Token::new_infix_op(&s, true, 5),
            "/" => Token::new_infix_op(&s, true, 5),
            "%" => Token::new_infix_op(&s, true, 5),

            "+" => Token::new_infix_op(&s, true, 4),
            "-" => Token::new_infix_op(&s, true, 4),

            "=" => Token::new_infix_op(&s, true, 3),
            "!=" => Token::new_infix_op(&s, true, 3),
            "<" => Token::new_infix_op(&s, true, 3),
            ">" => Token::new_infix_op(&s, true, 3),
            "<=" => Token::new_infix_op(&s, true, 3),
            ">=" => Token::new_infix_op(&s, true, 3),

            "&" => Token::new_infix_op(&s, true, 2),

            "|" => Token::new_infix_op(&s, true, 1),

            "match" => Token::PrefixOp {
                arity: 2,
                value: s.clone(),
            },
            "substr" => Token::PrefixOp {
                arity: 3,
                value: s.clone(),
            },
            "index" => Token::PrefixOp {
                arity: 2,
                value: s.clone(),
            },
            "length" => Token::PrefixOp {
                arity: 1,
                value: s.clone(),
            },

            _ => Token::new_value(&s),
        };
        push_token_if_not_escaped(&mut tokens_acc, tok_idx, token_if_not_escaped, &s);
        tok_idx += 1;
    }
    maybe_dump_tokens_acc(&tokens_acc);

    Ok(tokens_acc)
}

fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) {
    use std::env;

    if let Ok(debug_var) = env::var("EXPR_DEBUG_TOKENS") {
        if debug_var == "1" {
            println!("EXPR_DEBUG_TOKENS");
            for token in tokens_acc {
                println!("\t{:?}", token);
            }
        }
    }
}

fn push_token_if_not_escaped(
    acc: &mut Vec<(usize, Token)>,
    tok_idx: usize,
    token: Token,
    s: &str,
) {
    // Smells heuristics... :(
    let prev_is_plus = match acc.last() {
        None => false,
        Some(ref t) => t.1.is_infix_plus(),
    };
    let should_use_as_escaped = if prev_is_plus && acc.len() >= 2 {
        let pre_prev = &acc[acc.len() - 2];
        !(pre_prev.1.is_a_number() || pre_prev.1.is_a_close_paren())
    } else {
        prev_is_plus
    };

    if should_use_as_escaped {
        acc.pop();
        acc.push((tok_idx, Token::new_value(s)))
    } else {
        acc.push((tok_idx, token))
    }
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (use is_ok)<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

//!
//! The following tokens are present in the expr grammar:
//! * integer literal;
//! * string literal;
//! * infix binary operators;
//! * prefix operators.
//!
//! According to the man-page of expr we have expression split into tokens (each token -- separate CLI-argument).
//! Hence all we need is to map the strings into the Token structures, except for some ugly fiddling with +-escaping.
//!

#[derive(Debug, Clone)]
pub enum Token {
    Value {
        value: String,
    },

    ParOpen,
    ParClose,

    InfixOp {
        precedence: u8,
        left_assoc: bool,
        value: String,
    },

    PrefixOp {
        arity: usize,
        value: String,
    },
}
impl Token {
    fn new_infix_op(v: &str, left_assoc: bool, precedence: u8) -> Self {
        Token::InfixOp {
            left_assoc,
            precedence,
            value: v.into(),
        }
    }
    fn new_value(v: &str) -> Self {
        Token::Value { value: v.into() }
    }

    fn is_infix_plus(&self) -> bool {
        match *self {
            Token::InfixOp { ref value, .. } => value == "+",
            _ => false,
        }
    }
    fn is_a_number(&self) -> bool {
        match *self {
            Token::Value { ref value, .. } => value.parse::<i64>().is_ok(),
            _ => false,
        }
    }
    fn is_a_close_paren(&self) -> bool {
        match *self {
            Token::ParClose => true,
            _ => false,
        }
    }
}

pub fn strings_to_tokens(strings: &[String]) -> Result<Vec<(usize, Token)>, String> {
    let mut tokens_acc = Vec::with_capacity(strings.len());
    let mut tok_idx = 1;

    for s in strings {
        let token_if_not_escaped = match s.as_ref() {
            "(" => Token::ParOpen,
            ")" => Token::ParClose,

            "^" => Token::new_infix_op(&s, false, 7),

            ":" => Token::new_infix_op(&s, true, 6),

            "*" => Token::new_infix_op(&s, true, 5),
            "/" => Token::new_infix_op(&s, true, 5),
            "%" => Token::new_infix_op(&s, true, 5),

            "+" => Token::new_infix_op(&s, true, 4),
            "-" => Token::new_infix_op(&s, true, 4),

            "=" => Token::new_infix_op(&s, true, 3),
            "!=" => Token::new_infix_op(&s, true, 3),
            "<" => Token::new_infix_op(&s, true, 3),
            ">" => Token::new_infix_op(&s, true, 3),
            "<=" => Token::new_infix_op(&s, true, 3),
            ">=" => Token::new_infix_op(&s, true, 3),

            "&" => Token::new_infix_op(&s, true, 2),

            "|" => Token::new_infix_op(&s, true, 1),

            "match" => Token::PrefixOp {
                arity: 2,
                value: s.clone(),
            },
            "substr" => Token::PrefixOp {
                arity: 3,
                value: s.clone(),
            },
            "index" => Token::PrefixOp {
                arity: 2,
                value: s.clone(),
            },
            "length" => Token::PrefixOp {
                arity: 1,
                value: s.clone(),
            },

            _ => Token::new_value(&s),
        };
        push_token_if_not_escaped(&mut tokens_acc, tok_idx, token_if_not_escaped, &s);
        tok_idx += 1;
    }
    maybe_dump_tokens_acc(&tokens_acc);

    Ok(tokens_acc)
}

fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) {
    use std::env;

    if let Ok(debug_var) = env::var("EXPR_DEBUG_TOKENS") {
        if debug_var == "1" {
            println!("EXPR_DEBUG_TOKENS");
            for token in tokens_acc {
                println!("\t{:?}", token);
            }
        }
    }
}

fn push_token_if_not_escaped(
    acc: &mut Vec<(usize, Token)>,
    tok_idx: usize,
    token: Token,
    s: &str,
) {
    // Smells heuristics... :(
    let prev_is_plus = match acc.last() {
        None => false,
        Some(ref t) => t.1.is_infix_plus(),
    };
    let should_use_as_escaped = if prev_is_plus && acc.len() >= 2 {
        let pre_prev = &acc[acc.len() - 2];
        !(pre_prev.1.is_a_number() || pre_prev.1.is_a_close_paren())
    } else {
        prev_is_plus
    };

    if should_use_as_escaped {
        acc.pop();
        acc.push((tok_idx, Token::new_value(s)))
    } else {
        acc.push((tok_idx, token))
    }
}
<|endoftext|>


<commit_before>use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::sync::Arc;

use texture::{mod, Texture};
use uniforms::Uniforms;
use {DisplayImpl, VertexBuffer, IndexBuffer, Program, DrawParameters, Surface};
use {FrameBufferObject};

use {vertex_buffer, index_buffer, program};
use {gl, context, libc};

/// Creates a framebuffer that allows you to draw on something.
pub struct FrameBuffer<'a> {
    display: Arc<DisplayImpl>,
    attachments: FramebufferAttachments,
    marker: ContravariantLifetime<'a>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new<'a>(display: &::Display) -> FrameBuffer<'a> {
        FrameBuffer {
            display: display.context.clone(),
            attachments: FramebufferAttachments {
                colors: Vec::new(),
                depth: None,
                stencil: None
            },
            marker: ContravariantLifetime
        }
    }

    pub fn with_texture<T: 'a>(mut self, texture: &'a mut T) -> FrameBuffer<'a> where T: Texture {
        self.attachments.colors.push(texture::get_id(texture.get_implementation()));
        self
    }
}

impl<'a> Surface for FrameBuffer<'a> {
    fn clear_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        clear_color(&self.display, Some(&self.attachments), red, green, blue, alpha)
    }

    fn clear_depth(&mut self, value: f32) {
        clear_depth(&self.display, Some(&self.attachments), value)
    }

    fn clear_stencil(&mut self, value: int) {
        clear_stencil(&self.display, Some(&self.attachments), value)
    }

    fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }

    fn draw<V, U>(&mut self, vb: &::VertexBuffer<V>, ib: &::IndexBuffer, program: &::Program,
        uniforms: &U, draw_parameters: &::DrawParameters) where U: ::uniforms::Uniforms
    {
        draw(&self.display, Some(&self.attachments), vb, ib, program, uniforms, draw_parameters)
    }
}

#[deriving(Hash, Clone, PartialEq, Eq)]
pub struct FramebufferAttachments {
    colors: Vec<gl::types::GLuint>,
    depth: Option<gl::types::GLuint>,
    stencil: Option<gl::types::GLuint>,
}

/// Draws everything.
pub fn draw<V, U: Uniforms>(display: &Arc<DisplayImpl>,
    framebuffer: Option<&FramebufferAttachments>, vertex_buffer: &VertexBuffer<V>,
    index_buffer: &IndexBuffer, program: &Program, uniforms: &U, draw_parameters: &DrawParameters)
{
    let fbo_id = get_framebuffer(display, framebuffer);

    let (vb_id, vb_elementssize, vb_bindingsclone) = vertex_buffer::get_clone(vertex_buffer);
    let (ib_id, ib_elemcounts, ib_datatype, ib_primitives) =
        index_buffer::get_clone(index_buffer);
    let program_id = program::get_program_id(program);
    let uniforms = uniforms.to_binder();
    let uniforms_locations = program::get_uniforms_locations(program);
    let draw_parameters = draw_parameters.clone();

    let (tx, rx) = channel();

    display.context.exec(proc(gl, state, version, extensions) {
        unsafe {
            bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

            // binding program
            if state.program != program_id {
                gl.UseProgram(program_id);
                state.program = program_id;
            }

            // binding program uniforms
            uniforms.0(gl, |name| {
                uniforms_locations
                    .find_equiv(name)
                    .map(|val| val.0)
            });

            // binding vertex buffer
            if state.array_buffer_binding != Some(vb_id) {
                gl.BindBuffer(gl::ARRAY_BUFFER, vb_id);
                state.array_buffer_binding = Some(vb_id);
            }

            // binding index buffer
            if state.element_array_buffer_binding != Some(ib_id) {
                gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ib_id);
                state.element_array_buffer_binding = Some(ib_id);
            }

            // binding vertex buffer
            let mut locations = Vec::new();
            for &(ref name, vertex_buffer::VertexAttrib { offset, data_type, elements_count })
                in vb_bindingsclone.iter()
            {
                let loc = gl.GetAttribLocation(program_id, name.to_c_str().unwrap());
                locations.push(loc);

                if loc != -1 {
                    match data_type {
                        gl::BYTE | gl::UNSIGNED_BYTE | gl::SHORT | gl::UNSIGNED_SHORT |
                        gl::INT | gl::UNSIGNED_INT =>
                            gl.VertexAttribIPointer(loc as u32,
                                elements_count as gl::types::GLint, data_type,
                                vb_elementssize as i32, offset as *const libc::c_void),

                        _ => gl.VertexAttribPointer(loc as u32,
                                elements_count as gl::types::GLint, data_type, 0,
                                vb_elementssize as i32, offset as *const libc::c_void)
                    }

                    gl.EnableVertexAttribArray(loc as u32);
                }
            }

            // sync-ing parameters
            draw_parameters.sync(gl, state);

            // drawing
            gl.DrawElements(ib_primitives, ib_elemcounts as i32, ib_datatype, ptr::null());

            // disable vertex attrib array
            for l in locations.iter() {
                gl.DisableVertexAttribArray(l.clone() as u32);
            }
        }

        tx.send(());
    });

    // synchronizing with the end of the draw
    // TODO: remove that after making sure that everything is ok
    rx.recv();
}

pub fn clear_color(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    red: f32, green: f32, blue: f32, alpha: f32)
{
    let fbo_id = get_framebuffer(display, framebuffer);

    let (red, green, blue, alpha) = (
        red as gl::types::GLclampf,
        green as gl::types::GLclampf,
        blue as gl::types::GLclampf,
        alpha as gl::types::GLclampf
    );

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_color != (red, green, blue, alpha) {
            gl.ClearColor(red, green, blue, alpha);
            state.clear_color = (red, green, blue, alpha);
        }

        gl.Clear(gl::COLOR_BUFFER_BIT);
    });
}

pub fn clear_depth(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    value: f32)
{
    let value = value as gl::types::GLclampf;
    let fbo_id = get_framebuffer(display, framebuffer);

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_depth != value {
            gl.ClearDepth(value as f64);        // TODO: find out why this needs "as"
            state.clear_depth = value;
        }

        gl.Clear(gl::DEPTH_BUFFER_BIT);
    });
}

pub fn clear_stencil(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    value: int)
{
    let value = value as gl::types::GLint;
    let fbo_id = get_framebuffer(display, framebuffer);

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_stencil != value {
            gl.ClearStencil(value);
            state.clear_stencil = value;
        }

        gl.Clear(gl::STENCIL_BUFFER_BIT);
    });
}

fn get_framebuffer(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>)
    -> Option<gl::types::GLuint>
{
    if let Some(framebuffer) = framebuffer {
        let mut framebuffers = display.framebuffer_objects.lock();

        if let Some(value) = framebuffers.find(framebuffer) {
            return Some(value.id);
        }

        let mut new_fbo = FrameBufferObject::new(display.clone());
        let new_fbo_id = new_fbo.id.clone();
        initialize_fbo(display, &mut new_fbo, framebuffer);
        framebuffers.insert(framebuffer.clone(), new_fbo);
        Some(new_fbo_id)

    } else {
        None
    }
}

fn initialize_fbo(display: &Arc<DisplayImpl>, fbo: &mut FrameBufferObject,
    content: &FramebufferAttachments)
{
    // TODO: missing implementation
}

fn bind_framebuffer(gl: &gl::Gl, state: &mut context::GLState, version: &context::GlVersion,
    _: &context::ExtensionsList, fbo_id: Option<gl::types::GLuint>, draw: bool, read: bool)
{
    if draw && state.draw_framebuffer != fbo_id {
        if version >= &context::GlVersion(3, 0) {
            gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
        } else {
            gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
            state.read_framebuffer = fbo_id.clone();
        }
    }

    if read && state.read_framebuffer != fbo_id {
        if version >= &context::GlVersion(3, 0) {
            gl.BindFramebuffer(gl::READ_FRAMEBUFFER, fbo_id.unwrap_or(0));
            state.read_framebuffer = fbo_id.clone();
        } else {
            gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
            state.read_framebuffer = fbo_id.clone();
        }
    }
}
<commit_msg>Implement initialize_fbo<commit_after>use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::sync::Arc;

use texture::{mod, Texture};
use uniforms::Uniforms;
use {DisplayImpl, VertexBuffer, IndexBuffer, Program, DrawParameters, Surface};
use {FrameBufferObject};

use {vertex_buffer, index_buffer, program};
use {gl, context, libc};

/// Creates a framebuffer that allows you to draw on something.
pub struct FrameBuffer<'a> {
    display: Arc<DisplayImpl>,
    attachments: FramebufferAttachments,
    marker: ContravariantLifetime<'a>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new<'a>(display: &::Display) -> FrameBuffer<'a> {
        FrameBuffer {
            display: display.context.clone(),
            attachments: FramebufferAttachments {
                colors: Vec::new(),
                depth: None,
                stencil: None
            },
            marker: ContravariantLifetime
        }
    }

    pub fn with_texture<T: 'a>(mut self, texture: &'a mut T) -> FrameBuffer<'a> where T: Texture {
        self.attachments.colors.push(texture::get_id(texture.get_implementation()));
        self
    }
}

impl<'a> Surface for FrameBuffer<'a> {
    fn clear_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        clear_color(&self.display, Some(&self.attachments), red, green, blue, alpha)
    }

    fn clear_depth(&mut self, value: f32) {
        clear_depth(&self.display, Some(&self.attachments), value)
    }

    fn clear_stencil(&mut self, value: int) {
        clear_stencil(&self.display, Some(&self.attachments), value)
    }

    fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }

    fn draw<V, U>(&mut self, vb: &::VertexBuffer<V>, ib: &::IndexBuffer, program: &::Program,
        uniforms: &U, draw_parameters: &::DrawParameters) where U: ::uniforms::Uniforms
    {
        draw(&self.display, Some(&self.attachments), vb, ib, program, uniforms, draw_parameters)
    }
}

#[deriving(Hash, Clone, PartialEq, Eq)]
pub struct FramebufferAttachments {
    colors: Vec<gl::types::GLuint>,
    depth: Option<gl::types::GLuint>,
    stencil: Option<gl::types::GLuint>,
}

/// Draws everything.
pub fn draw<V, U: Uniforms>(display: &Arc<DisplayImpl>,
    framebuffer: Option<&FramebufferAttachments>, vertex_buffer: &VertexBuffer<V>,
    index_buffer: &IndexBuffer, program: &Program, uniforms: &U, draw_parameters: &DrawParameters)
{
    let fbo_id = get_framebuffer(display, framebuffer);

    let (vb_id, vb_elementssize, vb_bindingsclone) = vertex_buffer::get_clone(vertex_buffer);
    let (ib_id, ib_elemcounts, ib_datatype, ib_primitives) =
        index_buffer::get_clone(index_buffer);
    let program_id = program::get_program_id(program);
    let uniforms = uniforms.to_binder();
    let uniforms_locations = program::get_uniforms_locations(program);
    let draw_parameters = draw_parameters.clone();

    let (tx, rx) = channel();

    display.context.exec(proc(gl, state, version, extensions) {
        unsafe {
            bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

            // binding program
            if state.program != program_id {
                gl.UseProgram(program_id);
                state.program = program_id;
            }

            // binding program uniforms
            uniforms.0(gl, |name| {
                uniforms_locations
                    .find_equiv(name)
                    .map(|val| val.0)
            });

            // binding vertex buffer
            if state.array_buffer_binding != Some(vb_id) {
                gl.BindBuffer(gl::ARRAY_BUFFER, vb_id);
                state.array_buffer_binding = Some(vb_id);
            }

            // binding index buffer
            if state.element_array_buffer_binding != Some(ib_id) {
                gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ib_id);
                state.element_array_buffer_binding = Some(ib_id);
            }

            // binding vertex buffer
            let mut locations = Vec::new();
            for &(ref name, vertex_buffer::VertexAttrib { offset, data_type, elements_count })
                in vb_bindingsclone.iter()
            {
                let loc = gl.GetAttribLocation(program_id, name.to_c_str().unwrap());
                locations.push(loc);

                if loc != -1 {
                    match data_type {
                        gl::BYTE | gl::UNSIGNED_BYTE | gl::SHORT | gl::UNSIGNED_SHORT |
                        gl::INT | gl::UNSIGNED_INT =>
                            gl.VertexAttribIPointer(loc as u32,
                                elements_count as gl::types::GLint, data_type,
                                vb_elementssize as i32, offset as *const libc::c_void),

                        _ => gl.VertexAttribPointer(loc as u32,
                                elements_count as gl::types::GLint, data_type, 0,
                                vb_elementssize as i32, offset as *const libc::c_void)
                    }

                    gl.EnableVertexAttribArray(loc as u32);
                }
            }

            // sync-ing parameters
            draw_parameters.sync(gl, state);

            // drawing
            gl.DrawElements(ib_primitives, ib_elemcounts as i32, ib_datatype, ptr::null());

            // disable vertex attrib array
            for l in locations.iter() {
                gl.DisableVertexAttribArray(l.clone() as u32);
            }
        }

        tx.send(());
    });

    // synchronizing with the end of the draw
    // TODO: remove that after making sure that everything is ok
    rx.recv();
}

pub fn clear_color(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    red: f32, green: f32, blue: f32, alpha: f32)
{
    let fbo_id = get_framebuffer(display, framebuffer);

    let (red, green, blue, alpha) = (
        red as gl::types::GLclampf,
        green as gl::types::GLclampf,
        blue as gl::types::GLclampf,
        alpha as gl::types::GLclampf
    );

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_color != (red, green, blue, alpha) {
            gl.ClearColor(red, green, blue, alpha);
            state.clear_color = (red, green, blue, alpha);
        }

        gl.Clear(gl::COLOR_BUFFER_BIT);
    });
}

pub fn clear_depth(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    value: f32)
{
    let value = value as gl::types::GLclampf;
    let fbo_id = get_framebuffer(display, framebuffer);

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_depth != value {
            gl.ClearDepth(value as f64);        // TODO: find out why this needs "as"
            state.clear_depth = value;
        }

        gl.Clear(gl::DEPTH_BUFFER_BIT);
    });
}

pub fn clear_stencil(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>,
    value: int)
{
    let value = value as gl::types::GLint;
    let fbo_id = get_framebuffer(display, framebuffer);

    display.context.exec(proc(gl, state, version, extensions) {
        bind_framebuffer(gl, state, version, extensions, fbo_id, true, false);

        if state.clear_stencil != value {
            gl.ClearStencil(value);
            state.clear_stencil = value;
        }

        gl.Clear(gl::STENCIL_BUFFER_BIT);
    });
}

fn get_framebuffer(display: &Arc<DisplayImpl>, framebuffer: Option<&FramebufferAttachments>)
    -> Option<gl::types::GLuint>
{
    if let Some(framebuffer) = framebuffer {
        let mut framebuffers = display.framebuffer_objects.lock();

        if let Some(value) = framebuffers.find(framebuffer) {
            return Some(value.id);
        }

        let mut new_fbo = FrameBufferObject::new(display.clone());
        let new_fbo_id = new_fbo.id.clone();
        initialize_fbo(display, &mut new_fbo, framebuffer);
        framebuffers.insert(framebuffer.clone(), new_fbo);
        Some(new_fbo_id)

    } else {
        None
    }
}

fn initialize_fbo(display: &Arc<DisplayImpl>, fbo: &mut FrameBufferObject,
    content: &FramebufferAttachments)
{
    use context::GlVersion;

    let fbo_id = fbo.id;

    if content.depth.is_some() { unimplemented!() }
    if content.stencil.is_some() { unimplemented!() }

    for (slot, texture) in content.colors.iter().enumerate() {
        let tex_id = texture.clone();

        display.context.exec(proc(gl, state, version, extensions) {
            if version >= &GlVersion(4, 5) {
                gl.NamedFramebufferTexture(fbo_id, gl::COLOR_ATTACHMENT0 + slot as u32, tex_id, 0);

            } else if extensions.gl_ext_direct_state_access &&
                      extensions.gl_ext_geometry_shader4
            {
                gl.NamedFramebufferTextureEXT(fbo_id, gl::COLOR_ATTACHMENT0 + slot as u32, tex_id,
                    0);

            } else if version >= &GlVersion(3, 2) {
                bind_framebuffer(gl, state, version, extensions, Some(fbo_id), true, false);
                gl.FramebufferTexture(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + slot as u32,
                    tex_id, 0);

            } else if version >= &GlVersion(3, 0) {
                bind_framebuffer(gl, state, version, extensions, Some(fbo_id), true, false);
                gl.FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + slot as u32,
                    gl::TEXTURE_2D, tex_id, 0);

            } else {
                bind_framebuffer(gl, state, version, extensions, Some(fbo_id), true, true);
                gl.FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT, gl::COLOR_ATTACHMENT0 + slot as u32,
                    gl::TEXTURE_2D, tex_id, 0);
            }
        });
    }
}

fn bind_framebuffer(gl: &gl::Gl, state: &mut context::GLState, version: &context::GlVersion,
    _: &context::ExtensionsList, fbo_id: Option<gl::types::GLuint>, draw: bool, read: bool)
{
    if draw && state.draw_framebuffer != fbo_id {
        if version >= &context::GlVersion(3, 0) {
            gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
        } else {
            gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
            state.read_framebuffer = fbo_id.clone();
        }
    }

    if read && state.read_framebuffer != fbo_id {
        if version >= &context::GlVersion(3, 0) {
            gl.BindFramebuffer(gl::READ_FRAMEBUFFER, fbo_id.unwrap_or(0));
            state.read_framebuffer = fbo_id.clone();
        } else {
            gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id.unwrap_or(0));
            state.draw_framebuffer = fbo_id.clone();
            state.read_framebuffer = fbo_id.clone();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix bug in number spaces before units<commit_after><|endoftext|>


<commit_before><commit_msg>librand: Remove all uses of `~str` from `librand`<commit_after><|endoftext|>


<commit_before>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemConstVirtualPtr<U> {
        PmemConstVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemMutVirtualPtr<U> {
        PmemMutVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        self.pool.offset(self.virt.offset as isize) as *const T
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemConstPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemConstPtr<U> {
        let new_virt = self.virt.as_type();
        PmemConstPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        self.pool.offset(self.virt.offset as isize) as *mut T
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemMutPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemMutPtr<U> {
        let new_virt = self.virt.as_type();
        PmemMutPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<commit_msg>feat: imrpoved nulls<commit_after>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemConstVirtualPtr<U> {
        PmemConstVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }

    pub unsafe fn as_type<U>(self) -> PmemMutVirtualPtr<U> {
        PmemMutVirtualPtr { poolid: self.poolid, offset: self.offset, _t: PhantomData }
    }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T: ?Sized> PmemConstPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        if self.is_null() {
            ::std::ptr::null()
        } else {
            self.pool.offset(self.virt.offset as isize) as *const T
        }
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemConstPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemConstPtr<U> {
        let new_virt = self.virt.as_type();
        PmemConstPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T: ?Sized> PmemMutPtr<T> {
    pub fn is_null(&self) -> bool { self.virt.is_null() }
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        if self.is_null() {
            ::std::ptr::null_mut()
        } else {
            self.pool.offset(self.virt.offset as isize) as *mut T
        }
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemMutPtr { virt: new_virt, pool: self.pool }
    }

    pub unsafe fn as_type<U>(self) -> PmemMutPtr<U> {
        let new_virt = self.virt.as_type();
        PmemMutPtr { virt: new_virt, pool: self.pool as *mut U }
    }
}

pub fn null<T>() -> PmemConstVirtualPtr<T> {
    PmemConstVirtualPtr::null()
}

pub fn null_mut<T>() -> PmemMutVirtualPtr<T> {
    PmemMutVirtualPtr::null()
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<|endoftext|>