<commit_before>use imageflow_helpers::preludes::from_std::*;
use imageflow_types as s;

pub mod parsing;
mod layout;

use crate::sizing;
use crate::sizing::prelude::*;
use crate::ir4::parsing::*;
use crate::ir4::layout::*;

pub use layout::ConstraintResults;

pub fn process_constraint(source_w: i32, source_h: i32, constraint: &imageflow_types::Constraint) -> sizing::Result<ConstraintResults>{
    layout::Ir4Layout::process_constraint(source_w,source_h, constraint)
}

pub enum Ir4Command{
    Instructions(Box<Instructions>),
    Url(String),
    QueryString(String)
}

impl Ir4Command{
    pub fn parse(&self) -> sizing::Result<Ir4Result> {
        let (i, warn) = match *self {
            Ir4Command::Url(ref url) => parsing::parse_url(&::url::Url::from_str(url).expect("ImageResizer4 Url cannot be parsed into instructions: invalid URI")),
            Ir4Command::Instructions(ref i) => (**i, vec![]),
            Ir4Command::QueryString(ref s) => {
                let url = ::url::Url::from_str(&format!("https://fakeurl/img.jpg?{}", s)).expect("Must be a valid querystring, excluding ?");
                parsing::parse_url(&url)
            }
        };
        Ok(Ir4Result{
            parse_warnings: warn,
            parsed: i,
            steps: None,
            canvas: None
        })
    }

}

/// Minimal translation into framewise (delay as much as possible)
pub struct Ir4Translate{
    pub i: Ir4Command,
    pub decode_id: Option<i32>,
    pub encode_id: Option<i32>,
}

// If using trim.threshold, delayed expansion is required.

pub struct Ir4Result{
    pub parse_warnings: Vec<parsing::ParseWarning>,
    pub parsed: Instructions,
    pub steps: Option<Vec<s::Node>>,
    pub canvas: Option<AspectRatio>
}

impl Ir4Translate{

    pub fn get_decode_node(&self) -> Option<s::Node>{
        if let Some(id) = self.decode_id {
            Some(s::Node::Decode { io_id: id, commands: None })
        }else{
            None
        }
    }

    pub fn translate(&self) -> sizing::Result<Ir4Result> {
        let mut r = self.i.parse()?;
        let mut b = crate::ir4::layout::FramewiseBuilder::new();
        //Expand decoder early if trimming
        let delayed_id = if r.parsed.trim_whitespace_threshold.is_some() {
            if let Some(n) = self.get_decode_node() {
                b.add(n);
            }
            None
        } else {
            self.decode_id
        };
        // Add CropWhitespace
        if r.parsed.trim_whitespace_threshold.is_some(){
            b.add(s::Node::CropWhitespace {
                threshold: cmp::max(0,r.parsed.trim_whitespace_threshold.unwrap()) as u32,
                percent_padding: r.parsed.trim_whitespace_padding_percent.unwrap_or(0f64) as f32
            });
        }

        //delete whitespace from instructions
        let mut without_trimming: Instructions = r.parsed;
        without_trimming.trim_whitespace_padding_percent = None;
        without_trimming.trim_whitespace_threshold = None;

        b.add(s::Node::CommandString {
            kind: s::CommandStringKind::ImageResizer4,
            value: without_trimming.to_string(),
            decode: delayed_id,
            encode: self.encode_id
        });

        r.steps = Some(b.into_steps());
        Ok(r)
    }
}

pub struct Ir4SourceFrameInfo{
    pub w: i32,
    pub h: i32,
    pub fmt: s::PixelFormat,
    pub original_mime: Option<String>,
}

impl Ir4SourceFrameInfo{

    fn get_format_from_mime(&self) -> Option<OutputFormat>{
        self.original_mime.as_ref().and_then(|f|
                    match f.as_str(){
                        "image/jpeg" => Some(OutputFormat::Jpeg),
                        "image/png" => Some(OutputFormat::Png),
                        "image/gif" => Some(OutputFormat::Gif),
                        "image/webp" => Some(OutputFormat::Webp),
                        _ => None
                    })
    }
    fn get_format_from_frame(&self) -> OutputFormat{
        match self.fmt{
            s::PixelFormat::Bgr24 | s::PixelFormat::Bgr32 => OutputFormat::Jpeg,
            _ => OutputFormat::Png
        }
    }
}

/// Cannot expand decoder. use `Ir4Translate` for that.
pub struct Ir4Expand{
    pub i: Ir4Command,
    pub source: Ir4SourceFrameInfo,
    pub encode_id: Option<i32>,

}

impl Ir4Expand{

    pub fn get_decode_commands(&self) -> sizing::Result<Option<Vec<s::DecoderCommand>>> { //TODO: consider smallvec or generalizing decoder hints
        let i = self.i.parse()?.parsed;

        // Default to gamma correct
        let gamma_correct = i.down_colorspace != Some(ScalingColorspace::Srgb);

        let layout = self.get_layout(&i)?;
        let (from, to): (AspectRatio, AspectRatio) = layout.get_downscaling()?;

        let downscale_ratio = (f64::from(from.w) / f64::from(to.w)).min(f64::from(from.h) / f64::from(to.w));

        let preshrink_ratio = i.min_precise_scaling_ratio.unwrap_or(2.1f64) / downscale_ratio;

        let scaled_width = (f64::from(self.source.w) * preshrink_ratio).floor() as i64;
        let scaled_height = (f64::from(self.source.h) * preshrink_ratio).floor() as i64;
        if preshrink_ratio < 1f64 {
            let mut vec = Vec::with_capacity(2);
            vec.push(s::DecoderCommand::JpegDownscaleHints(s::JpegIDCTDownscaleHints {
                scale_luma_spatially: Some(gamma_correct),
                gamma_correct_for_srgb_during_spatial_luma_scaling: Some(gamma_correct),
                width: scaled_width,
                height: scaled_height
            }));
            if !gamma_correct{
                vec.push(s::DecoderCommand::WebPDecoderHints(s::WebPDecoderHints{
                    width: scaled_width as i32,
                    height: scaled_height as i32,
                }));
            }
            Ok(Some(vec))
        } else {
            Ok(None)
        }
    }

    pub fn get_canvas_size(&self) -> sizing::Result<AspectRatio>{
        let i = self.i.parse()?.parsed;
        let (_, layout) = self.get_layout(&i).unwrap().get_crop_and_layout().unwrap();
        Ok(layout.get_box(BoxTarget::CurrentCanvas))
    }

    pub fn get_layout(&self, i: &Instructions) -> sizing::Result<Ir4Layout> {
        if i.trim_whitespace_threshold.is_some() {
            return Err(sizing::LayoutError::ContentDependent);
        }
        Ok(layout::Ir4Layout::new(*i, self.source.w, self.source.h))
    }

    pub fn expand_steps(&self) -> sizing::Result<Ir4Result> {
        let mut r = self.i.parse()?;

        let layout = self.get_layout(&r.parsed)?;

        let mut b = FramewiseBuilder::new();
        r.canvas = Some(layout.add_steps(&mut b)?.canvas);

        if let Some(n) = self.get_encoder_node(&r.parsed) {
            b.add(n);
        }
        r.steps = Some(b.into_steps());
        Ok(r)

    }

    pub fn get_encoder_node(&self, i: &Instructions) -> Option<s::Node>{

        if let Some(id) = self.encode_id {

            let format = i.format.or_else(|| self.source.get_format_from_mime())
                .unwrap_or_else(|| self.source.get_format_from_frame());

            let png_lossless = i.png_lossless.unwrap_or(i.png_libpng == Some(true) ||
                i.png_quality.is_none());

            let encoder = match format {
                OutputFormat::Gif => s::EncoderPreset::Gif,
                OutputFormat::Jpeg if Some(true) == i.jpeg_turbo => s::EncoderPreset::LibjpegTurbo {
                    quality: Some(i.quality.unwrap_or(90)),
                    progressive: i.jpeg_progressive,
                    optimize_huffman_coding:  i.jpeg_progressive
                },
                OutputFormat::Jpeg=> s::EncoderPreset::Mozjpeg {
                    quality: Some(i.quality.unwrap_or(90) as u8),
                    progressive: i.jpeg_progressive
                },
                OutputFormat::Png if !png_lossless => s::EncoderPreset::Pngquant {
                    quality: Some(i.png_quality.unwrap_or(100)),
                    minimum_quality: Some(i.png_min_quality.unwrap_or(0)),
                    speed: i.png_quantization_speed,
                    maximum_deflate: i.png_max_deflate
                },
                OutputFormat::Png if i.png_libpng == Some(true) => s::EncoderPreset::Libpng {
                    depth: Some(if i.bgcolor_srgb.is_some() { s::PngBitDepth::Png24 } else { s::PngBitDepth::Png32 }),
                    zlib_compression: if i.png_max_deflate == Some(true) { Some(9) } else { None },
                    matte: i.bgcolor_srgb.map(|sr| s::Color::Srgb(s::ColorSrgb::Hex(sr.to_rrggbbaa_string())))
                },
                OutputFormat::Png => s::EncoderPreset::Lodepng{
                    maximum_deflate: i.png_max_deflate
                },
                OutputFormat::Webp if i.webp_lossless == Some(true) => s::EncoderPreset::WebPLossless,
                OutputFormat::Webp => s::EncoderPreset::WebPLossy {
                    quality: i.webp_quality.unwrap_or(90f64) as f32
                },
            };
            Some(s::Node::Encode { io_id: id, preset: encoder })
        }else{
            None
        }
    }
}

<commit_msg>Querystring API: change web.quality default to 80<commit_after>use imageflow_helpers::preludes::from_std::*;
use imageflow_types as s;

pub mod parsing;
mod layout;

use crate::sizing;
use crate::sizing::prelude::*;
use crate::ir4::parsing::*;
use crate::ir4::layout::*;

pub use layout::ConstraintResults;

pub fn process_constraint(source_w: i32, source_h: i32, constraint: &imageflow_types::Constraint) -> sizing::Result<ConstraintResults>{
    layout::Ir4Layout::process_constraint(source_w,source_h, constraint)
}

pub enum Ir4Command{
    Instructions(Box<Instructions>),
    Url(String),
    QueryString(String)
}

impl Ir4Command{
    pub fn parse(&self) -> sizing::Result<Ir4Result> {
        let (i, warn) = match *self {
            Ir4Command::Url(ref url) => parsing::parse_url(&::url::Url::from_str(url).expect("ImageResizer4 Url cannot be parsed into instructions: invalid URI")),
            Ir4Command::Instructions(ref i) => (**i, vec![]),
            Ir4Command::QueryString(ref s) => {
                let url = ::url::Url::from_str(&format!("https://fakeurl/img.jpg?{}", s)).expect("Must be a valid querystring, excluding ?");
                parsing::parse_url(&url)
            }
        };
        Ok(Ir4Result{
            parse_warnings: warn,
            parsed: i,
            steps: None,
            canvas: None
        })
    }

}

/// Minimal translation into framewise (delay as much as possible)
pub struct Ir4Translate{
    pub i: Ir4Command,
    pub decode_id: Option<i32>,
    pub encode_id: Option<i32>,
}

// If using trim.threshold, delayed expansion is required.

pub struct Ir4Result{
    pub parse_warnings: Vec<parsing::ParseWarning>,
    pub parsed: Instructions,
    pub steps: Option<Vec<s::Node>>,
    pub canvas: Option<AspectRatio>
}

impl Ir4Translate{

    pub fn get_decode_node(&self) -> Option<s::Node>{
        if let Some(id) = self.decode_id {
            Some(s::Node::Decode { io_id: id, commands: None })
        }else{
            None
        }
    }

    pub fn translate(&self) -> sizing::Result<Ir4Result> {
        let mut r = self.i.parse()?;
        let mut b = crate::ir4::layout::FramewiseBuilder::new();
        //Expand decoder early if trimming
        let delayed_id = if r.parsed.trim_whitespace_threshold.is_some() {
            if let Some(n) = self.get_decode_node() {
                b.add(n);
            }
            None
        } else {
            self.decode_id
        };
        // Add CropWhitespace
        if r.parsed.trim_whitespace_threshold.is_some(){
            b.add(s::Node::CropWhitespace {
                threshold: cmp::max(0,r.parsed.trim_whitespace_threshold.unwrap()) as u32,
                percent_padding: r.parsed.trim_whitespace_padding_percent.unwrap_or(0f64) as f32
            });
        }

        //delete whitespace from instructions
        let mut without_trimming: Instructions = r.parsed;
        without_trimming.trim_whitespace_padding_percent = None;
        without_trimming.trim_whitespace_threshold = None;

        b.add(s::Node::CommandString {
            kind: s::CommandStringKind::ImageResizer4,
            value: without_trimming.to_string(),
            decode: delayed_id,
            encode: self.encode_id
        });

        r.steps = Some(b.into_steps());
        Ok(r)
    }
}

pub struct Ir4SourceFrameInfo{
    pub w: i32,
    pub h: i32,
    pub fmt: s::PixelFormat,
    pub original_mime: Option<String>,
}

impl Ir4SourceFrameInfo{

    fn get_format_from_mime(&self) -> Option<OutputFormat>{
        self.original_mime.as_ref().and_then(|f|
                    match f.as_str(){
                        "image/jpeg" => Some(OutputFormat::Jpeg),
                        "image/png" => Some(OutputFormat::Png),
                        "image/gif" => Some(OutputFormat::Gif),
                        "image/webp" => Some(OutputFormat::Webp),
                        _ => None
                    })
    }
    fn get_format_from_frame(&self) -> OutputFormat{
        match self.fmt{
            s::PixelFormat::Bgr24 | s::PixelFormat::Bgr32 => OutputFormat::Jpeg,
            _ => OutputFormat::Png
        }
    }
}

/// Cannot expand decoder. use `Ir4Translate` for that.
pub struct Ir4Expand{
    pub i: Ir4Command,
    pub source: Ir4SourceFrameInfo,
    pub encode_id: Option<i32>,

}

impl Ir4Expand{

    pub fn get_decode_commands(&self) -> sizing::Result<Option<Vec<s::DecoderCommand>>> { //TODO: consider smallvec or generalizing decoder hints
        let i = self.i.parse()?.parsed;

        // Default to gamma correct
        let gamma_correct = i.down_colorspace != Some(ScalingColorspace::Srgb);

        let layout = self.get_layout(&i)?;
        let (from, to): (AspectRatio, AspectRatio) = layout.get_downscaling()?;

        let downscale_ratio = (f64::from(from.w) / f64::from(to.w)).min(f64::from(from.h) / f64::from(to.w));

        let preshrink_ratio = i.min_precise_scaling_ratio.unwrap_or(2.1f64) / downscale_ratio;

        let scaled_width = (f64::from(self.source.w) * preshrink_ratio).floor() as i64;
        let scaled_height = (f64::from(self.source.h) * preshrink_ratio).floor() as i64;
        if preshrink_ratio < 1f64 {
            let mut vec = Vec::with_capacity(2);
            vec.push(s::DecoderCommand::JpegDownscaleHints(s::JpegIDCTDownscaleHints {
                scale_luma_spatially: Some(gamma_correct),
                gamma_correct_for_srgb_during_spatial_luma_scaling: Some(gamma_correct),
                width: scaled_width,
                height: scaled_height
            }));
            if !gamma_correct{
                vec.push(s::DecoderCommand::WebPDecoderHints(s::WebPDecoderHints{
                    width: scaled_width as i32,
                    height: scaled_height as i32,
                }));
            }
            Ok(Some(vec))
        } else {
            Ok(None)
        }
    }

    pub fn get_canvas_size(&self) -> sizing::Result<AspectRatio>{
        let i = self.i.parse()?.parsed;
        let (_, layout) = self.get_layout(&i).unwrap().get_crop_and_layout().unwrap();
        Ok(layout.get_box(BoxTarget::CurrentCanvas))
    }

    pub fn get_layout(&self, i: &Instructions) -> sizing::Result<Ir4Layout> {
        if i.trim_whitespace_threshold.is_some() {
            return Err(sizing::LayoutError::ContentDependent);
        }
        Ok(layout::Ir4Layout::new(*i, self.source.w, self.source.h))
    }

    pub fn expand_steps(&self) -> sizing::Result<Ir4Result> {
        let mut r = self.i.parse()?;

        let layout = self.get_layout(&r.parsed)?;

        let mut b = FramewiseBuilder::new();
        r.canvas = Some(layout.add_steps(&mut b)?.canvas);

        if let Some(n) = self.get_encoder_node(&r.parsed) {
            b.add(n);
        }
        r.steps = Some(b.into_steps());
        Ok(r)

    }

    pub fn get_encoder_node(&self, i: &Instructions) -> Option<s::Node>{

        if let Some(id) = self.encode_id {

            let format = i.format.or_else(|| self.source.get_format_from_mime())
                .unwrap_or_else(|| self.source.get_format_from_frame());

            let png_lossless = i.png_lossless.unwrap_or(i.png_libpng == Some(true) ||
                i.png_quality.is_none());

            let encoder = match format {
                OutputFormat::Gif => s::EncoderPreset::Gif,
                OutputFormat::Jpeg if Some(true) == i.jpeg_turbo => s::EncoderPreset::LibjpegTurbo {
                    quality: Some(i.quality.unwrap_or(90)),
                    progressive: i.jpeg_progressive,
                    optimize_huffman_coding:  i.jpeg_progressive
                },
                OutputFormat::Jpeg=> s::EncoderPreset::Mozjpeg {
                    quality: Some(i.quality.unwrap_or(90) as u8),
                    progressive: i.jpeg_progressive
                },
                OutputFormat::Png if !png_lossless => s::EncoderPreset::Pngquant {
                    quality: Some(i.png_quality.unwrap_or(100)),
                    minimum_quality: Some(i.png_min_quality.unwrap_or(0)),
                    speed: i.png_quantization_speed,
                    maximum_deflate: i.png_max_deflate
                },
                OutputFormat::Png if i.png_libpng == Some(true) => s::EncoderPreset::Libpng {
                    depth: Some(if i.bgcolor_srgb.is_some() { s::PngBitDepth::Png24 } else { s::PngBitDepth::Png32 }),
                    zlib_compression: if i.png_max_deflate == Some(true) { Some(9) } else { None },
                    matte: i.bgcolor_srgb.map(|sr| s::Color::Srgb(s::ColorSrgb::Hex(sr.to_rrggbbaa_string())))
                },
                OutputFormat::Png => s::EncoderPreset::Lodepng{
                    maximum_deflate: i.png_max_deflate
                },
                OutputFormat::Webp if i.webp_lossless == Some(true) => s::EncoderPreset::WebPLossless,
                OutputFormat::Webp => s::EncoderPreset::WebPLossy {
                    quality: i.webp_quality.unwrap_or(80f64) as f32
                },
            };
            Some(s::Node::Encode { io_id: id, preset: encoder })
        }else{
            None
        }
    }
}

<|endoftext|>


<commit_before>//! This module provides some of the simplest exports
//! from the Emscripten runtime, such as `STACKTOP` or `abort`.

use std::sync::{Arc, Weak};
use std::collections::HashMap;
use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
	ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::native::{NATIVE_INDEX_FUNC_MIN, UserFunctionExecutor, UserDefinedElements, UserFunctionDescriptor, native_module};
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
	ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Memory address, at which stack base begins.
const DEFAULT_STACK_BASE: u32 = 0;
/// Memory address, at which stack begins.
const DEFAULT_STACK_TOP: u32 = 256 * 1024;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value.
const DEFAULT_MEMORY_BASE: u32 = 0;

/// Default table size.
const DEFAULT_TABLE_SIZE: u32 = 64;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

/// Index of STACK_BASE global variable.
const INDEX_GLOBAL_STACK_BASE: u32 = 0;
/// Index of STACK_TOP global variable.
const INDEX_GLOBAL_STACK_TOP: u32 = 1;
/// Index of STACK_MAX global variable.
const INDEX_GLOBAL_STACK_MAX: u32 = 2;
/// Index of DYNAMIC_BASE global variable.
const INDEX_GLOBAL_DYNAMIC_BASE: u32 = 3;
/// Index of DYNAMICTOP_PTR global variable.
const INDEX_GLOBAL_DYNAMICTOP_PTR: u32 = 4;
/// Index of TOTAL_MEMORY global variable.
const INDEX_GLOBAL_TOTAL_MEMORY: u32 = 5;
/// Index of ABORT global variable.
const INDEX_GLOBAL_ABORT: u32 = 6;
/// Index of EXITSTATUS global variable.
const INDEX_GLOBAL_EXIT_STATUS: u32 = 7;
/// Index of tableBase global variable.
const INDEX_GLOBAL_TABLE_BASE: u32 = 8;
/// Index of memoryBase global.
const INDEX_GLOBAL_MEMORY_BASE: u32 = 9;

/// Index of abort function.
const INDEX_FUNC_ABORT: u32 = 0;
/// Index of assert function.
const INDEX_FUNC_ASSERT: u32 = 1;
/// Index of enlargeMemory function.
const INDEX_FUNC_ENLARGE_MEMORY: u32 = 2;
/// Index of getTotalMemory function.
const INDEX_FUNC_GET_TOTAL_MEMORY: u32 = 3;
/// Min index of reserver function.
const INDEX_FUNC_MIN_NONUSED: u32 = 4;
/// Max index of reserved function.
const INDEX_FUNC_MAX: u32 = NATIVE_INDEX_FUNC_MIN - 1;

/// Emscripten environment parameters.
#[derive(Clone)]
pub struct EnvParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
	/// Table size.
	pub table_size: u32,
	/// Static reserve, if any
	pub static_size: Option<u32>,
}

struct EmscriptenFunctionExecutor {
	params: EnvParams,
}

impl<'a> UserFunctionExecutor for EmscriptenFunctionExecutor {
	 fn execute(
		 &mut self,
		 name: &str,
		 context: CallerContext,
	 ) -> Result<Option<RuntimeValue>, Error> {
		 match name {
			 _ => Err(Error::Trap("not implemented".into()).into()),
		 }
	 }
}

struct EmscriptenModuleInstance {
	_params: EnvParams,
	instance: ModuleInstance,
}

impl EmscriptenModuleInstance {
	pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
		let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;
		instance.instantiate(None)?;

		Ok(EmscriptenModuleInstance {
			_params: params,
			instance: instance,
		})
	}
}

impl ModuleInstanceInterface for EmscriptenModuleInstance {
	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_index(index, params)
	}

	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_export(name, params)
	}

	fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
		self.instance.export_entry(name, required_type)
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		self.instance.table(index)
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		self.instance.memory(index)
	}

	fn global<'a>(&self, index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<VariableInstance>, Error> {
		self.instance.global(index, variable_type, externals)
	}

	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
		self.instance.function_type(function_index)
	}

	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
		self.instance.function_type_by_index(type_index)
	}

	fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference(index, externals)
	}

	fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
	}

	fn function_body<'a>(&'a self, _internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error> {
		Ok(None)
	}

	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
		// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
		match index {
			INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None)
				.and_then(|g| g.set(RuntimeValue::I32(1)))
				.and_then(|_| Err(Error::Trap("abort".into())))
				.map_err(Into::into),
			INDEX_FUNC_ASSERT => outer.value_stack.pop_as::<i32>()
				.and_then(|condition| if condition == 0 {
					self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32), None)
						.and_then(|g| g.set(RuntimeValue::I32(1)))
						.and_then(|_| Err(Error::Trap("assertion failed".into())))
				} else {
					Ok(None)
				})
				.map_err(Into::into),
			INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge
			INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32), None)
				.map(|g| g.get())
				.map(Some)
				.map_err(Into::into),
			INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into()).into()),
			_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index)).into()),
		}
	}
}

pub fn env_module(params: EnvParams) -> Result<Arc<ModuleInstanceInterface>, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);
	let builder = module()
		// memory regions
		.memory()
			.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
			.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
			.build()
			.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
		// tables
		.table()
			.with_min(params.table_size)
			.build()
			.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)));
	let module = builder.build();

	let mut function_executor = EmscriptenFunctionExecutor {
		params: params.clone(),
	};

	const SIGNATURES: &'static [UserFunctionDescriptor] = &[
		UserFunctionDescriptor::Static(
			"getTotalMemory",
			&[],
			Some(ValueType::I32),
		),
		UserFunctionDescriptor::Static(
			"enlargeMemory",
			&[],
			Some(ValueType::I32),
		),
		UserFunctionDescriptor::Static(
			"assert",
			&[ValueType::I32],
			None,
		),
		UserFunctionDescriptor::Static(
			"abort",
			&[],
			None,
		),
	];

	let stack_top = params.static_size.unwrap_or(DEFAULT_STACK_TOP);

	let elements = UserDefinedElements {
		executor: Some(function_executor),
		globals: vec![
			("STACK_BASE".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(stack_top as i32)).unwrap())),
			("STACKTOP".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(stack_top as i32)).unwrap())),
			("STACK_MAX".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32((stack_top + params.total_stack) as i32)).unwrap())),
			("DYNAMIC_BASE".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32((stack_top + params.total_stack) as i32)).unwrap())),
			("DYNAMICTOP_PTR".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32((stack_top + params.total_stack) as i32)).unwrap())),
			("TOTAL_MEMORY".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(params.total_memory as i32)).unwrap())),
			("ABORT".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap())),
			("EXITSTATUS".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap())),
			("tableBase".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(DEFAULT_TABLE_BASE as i32)).unwrap())),
			("memoryBase".into(), Arc::new(VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(DEFAULT_MEMORY_BASE as i32)).unwrap())),
		].into_iter().collect(),
		functions: ::std::borrow::Cow::from(SIGNATURES),
	};

	let mut instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;
	instance.instantiate(None)?;

	Ok(native_module(Arc::new(instance), elements)?)
}

impl Default for EnvParams {
	fn default() -> Self {
		EnvParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
			table_size: DEFAULT_TABLE_SIZE,
			static_size: None,
		}
	}
}

impl EnvParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}
<commit_msg>Implement emscripten mod in terms of native mod<commit_after>//! This module provides some of the simplest exports
//! from the Emscripten runtime, such as `STACKTOP` or `abort`.

use std::sync::{Arc, Weak};
use builder::module;
use elements::{ExportEntry, Internal, ValueType};
use interpreter::Error;
use interpreter::native::{native_module, UserDefinedElements, UserFunctionDescriptor, UserFunctionExecutor};
use interpreter::module::{CallerContext, ModuleInstance, ModuleInstanceInterface};
use interpreter::memory::LINEAR_MEMORY_PAGE_SIZE;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Memory address, at which stack begins.
const DEFAULT_STACK_TOP: u32 = 256 * 1024;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value.
const DEFAULT_MEMORY_BASE: u32 = 0;

/// Default table size.
const DEFAULT_TABLE_SIZE: u32 = 64;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

/// Emscripten environment parameters.
pub struct EnvParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
	/// Table size.
	pub table_size: u32,
	/// Static reserve, if any
	pub static_size: Option<u32>,
}

struct EmscriptenFunctionExecutor {
	abort_global: Arc<VariableInstance>,
	total_mem_global: Arc<VariableInstance>,
}

impl<'a> UserFunctionExecutor for EmscriptenFunctionExecutor {
	fn execute(
		&mut self,
		name: &str,
		context: CallerContext,
	) -> Result<Option<RuntimeValue>, Error> {
		match name {
			"_abort" => {
				self.abort_global.set(RuntimeValue::I32(1))?;
				Err(Error::Trap("abort".into()).into())
			}
			"assert" => {
				let condition = context.value_stack.pop_as::<i32>()?;
				if condition == 0 {
					self.abort_global.set(RuntimeValue::I32(1))?;
					Err(Error::Trap("assertion failed".into()))
				} else {
					Ok(None)
				}
			}
			"enlargeMemory" => {
				// TODO: support memory enlarge
				Ok(Some(RuntimeValue::I32(0)))
			}
			"getTotalMemory" => {
				let total_memory = self.total_mem_global.get();
				Ok(Some(total_memory))
			}
			_ => Err(Error::Trap("not implemented".into()).into()),
		}
	}
}

pub fn env_module(params: EnvParams) -> Result<Arc<ModuleInstanceInterface>, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);

	let stack_top = params.static_size.unwrap_or(DEFAULT_STACK_TOP);

	// Build module with defined memory and table,
	// instantiate it and wrap into an Arc.
	let instance = {
		let builder = module()
			// memory regions
			.memory()
				.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
				.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
				.build()
				.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
			// tables
			.table()
				.with_min(params.table_size)
				.build()
				.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)));
		let mut instance = ModuleInstance::new(Weak::default(), "env".into(), builder.build())?;
		instance.instantiate(None)?;
		Arc::new(instance)
	};

	let abort_global = Arc::new(
		VariableInstance::new(
			false,
			VariableType::I32,
			RuntimeValue::I32(0)
		).unwrap()
	);
	let total_mem_global = Arc::new(
		VariableInstance::new(
			false,
			VariableType::I32,
			RuntimeValue::I32(params.total_memory as i32),
		).unwrap(),
	);

	let function_executor = EmscriptenFunctionExecutor {
		abort_global: Arc::clone(&abort_global),
		total_mem_global: Arc::clone(&total_mem_global),
	};

	const SIGNATURES: &'static [UserFunctionDescriptor] = &[
		UserFunctionDescriptor::Static("_abort", &[], None),
		UserFunctionDescriptor::Static("assert", &[ValueType::I32], None),
		UserFunctionDescriptor::Static("enlargeMemory", &[], Some(ValueType::I32)),
		UserFunctionDescriptor::Static("getTotalMemory", &[], Some(ValueType::I32)),
	];

	let elements = UserDefinedElements {
		executor: Some(function_executor),
		globals: vec![
			(
				"STACK_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACKTOP".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACK_MAX".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMIC_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMICTOP_PTR".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"EXITSTATUS".into(),
				Arc::new(
					VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap(),
				),
			),
			(
				"tableBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_TABLE_BASE as i32),
					).unwrap(),
				),
			),
			(
				"memoryBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_MEMORY_BASE as i32),
					).unwrap(),
				),
			),
			("TOTAL_MEMORY".into(), total_mem_global),
			("ABORT".into(), abort_global),
		].into_iter()
			.collect(),
		functions: ::std::borrow::Cow::from(SIGNATURES),
	};

	Ok(native_module(instance, elements)?)
}

impl Default for EnvParams {
	fn default() -> Self {
		EnvParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
			table_size: DEFAULT_TABLE_SIZE,
			static_size: None,
		}
	}
}

impl EnvParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}
<|endoftext|>


<commit_before>use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Reference, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Operation {
    Insert,     // insert text
    Delete,     // delete some object

    Undo,       // rewind buffer transaction log
    Redo,       // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Reference(Reference),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Show)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<uint>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    reference: Option<Reference>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Show)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            reference: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.reference = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        if let Some(to) = self.object {
            // we have a whole object ready
            return Some(to)
        } else if let Some(reference) = self.reference {
            // we have a particular object in mind, use number as index/offset
            let reference = if let Some(n) = self.number {
                // set the reference index to n, or multiply offset by n
                // also, reset the 'outer' number, since index/offset is separate from repeat counter
                self.number = None;
                match reference {
                    Reference::Index(k, _) => Reference::Index(k, n as u32),
                    Reference::Offset(m, k, i) => Reference::Offset(m, k, i * n),
                    Reference::Mark(m, k) => Reference::Mark(m, k)
                }
            } else { reference };
            self.reference = Some(reference);

            return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                     reference: reference })
        } else if let Some(kind) = self.kind {
            // we have a particular kind...
            if let Some(mark) = self.mark {
                // and a specific mark, return the object of that kind, at that mark
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Mark(mark, kind) })
            } else if let Some(n) = self.number {
                // and a particular number, return the nth of that kind
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Index(kind, n as u32) })
            }
        }
        None
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to kind at cursor n times                         |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or(TextObject {
                    anchor: Anchor::default(),
                    reference: Reference::default()
                })
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: uint) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Reference(r) => self.reference = Some(r),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    self.repeat = Some(self.number.unwrap() as uint);
                    self.number = None;
                }
            }
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char,  1)));
    keymap.bind_key(Key::Char('h'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char, -1)));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet),  1)));
    keymap.bind_key(Key::Char('b'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet), -1)));
    keymap.bind_key(Key::Char('W'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace),  1)));
    keymap.bind_key(Key::Char('B'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace), -1)));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(WordEdgeMatch::Alphabet)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('W')], Partial::Kind(Kind::Word(WordEdgeMatch::Whitespace)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line,  1)));
    keymap.bind_key(Key::Char('k'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line, -1)));

    // start/end of line
    keymap.bind_key(Key::Char('0'), Partial::Object(TextObject { anchor: Anchor::Before,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));
    keymap.bind_key(Key::Char('$'), Partial::Object(TextObject { anchor: Anchor::After,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));

    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));

    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<commit_msg>Add partial binds for `Kind`s and `Anchor`s<commit_after>use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Reference, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Operation {
    Insert,     // insert text
    Delete,     // delete some object

    Undo,       // rewind buffer transaction log
    Redo,       // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Reference(Reference),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Show)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<uint>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    reference: Option<Reference>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Show)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            reference: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.reference = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        if let Some(to) = self.object {
            // we have a whole object ready
            return Some(to)
        } else if let Some(reference) = self.reference {
            // we have a particular object in mind, use number as index/offset
            let reference = if let Some(n) = self.number {
                // set the reference index to n, or multiply offset by n
                // also, reset the 'outer' number, since index/offset is separate from repeat counter
                self.number = None;
                match reference {
                    Reference::Index(k, _) => Reference::Index(k, n as u32),
                    Reference::Offset(m, k, i) => Reference::Offset(m, k, i * n),
                    Reference::Mark(m, k) => Reference::Mark(m, k)
                }
            } else { reference };
            self.reference = Some(reference);

            return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                     reference: reference })
        } else if let Some(kind) = self.kind {
            // we have a particular kind...
            if let Some(mark) = self.mark {
                // and a specific mark, return the object of that kind, at that mark
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Mark(mark, kind) })
            } else if let Some(n) = self.number {
                // and a particular number, return the nth of that kind
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Index(kind, n as u32) })
            }
        }
        None
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to kind at cursor n times                         |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or(TextObject {
                    anchor: Anchor::default(),
                    reference: Reference::default()
                })
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: uint) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Reference(r) => self.reference = Some(r),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    self.repeat = Some(self.number.unwrap() as uint);
                    self.number = None;
                }
            }
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char,  1)));
    keymap.bind_key(Key::Char('h'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char, -1)));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet),  1)));
    keymap.bind_key(Key::Char('b'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet), -1)));
    keymap.bind_key(Key::Char('W'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace),  1)));
    keymap.bind_key(Key::Char('B'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace), -1)));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line,  1)));
    keymap.bind_key(Key::Char('k'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line, -1)));

    // start/end of line
    keymap.bind_key(Key::Char('0'), Partial::Object(TextObject { anchor: Anchor::Before,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));
    keymap.bind_key(Key::Char('$'), Partial::Object(TextObject { anchor: Anchor::After,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(WordEdgeMatch::Alphabet)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('W')], Partial::Kind(Kind::Word(WordEdgeMatch::Whitespace)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line));

    // anchors
    keymap.bind_key(Key::Char(','), Partial::Anchor(Anchor::Before));
    keymap.bind_key(Key::Char('.'), Partial::Anchor(Anchor::After));

    // actions
    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));
    keymap.bind_key(Key::Char('g'), Partial::Action(Action::Instruction(Instruction::SetMark(Mark::Cursor(0)))));

    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<|endoftext|>


<commit_before>use super::AttestationData;
use crate::test_utils::TestRandom;
use bls::AggregateSignature;
use rand::RngCore;
use serde_derive::Serialize;
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};

#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct SlashableVoteData {
    pub custody_bit_0_indices: Vec<u32>,
    pub custody_bit_1_indices: Vec<u32>,
    pub data: AttestationData,
    pub aggregate_signature: AggregateSignature,
}

impl Encodable for SlashableVoteData {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.custody_bit_0_indices);
        s.append_vec(&self.custody_bit_1_indices);
        s.append(&self.data);
        s.append(&self.aggregate_signature);
    }
}

impl Decodable for SlashableVoteData {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (custody_bit_0_indices, i) = <_>::ssz_decode(bytes, i)?;
        let (custody_bit_1_indices, i) = <_>::ssz_decode(bytes, i)?;
        let (data, i) = <_>::ssz_decode(bytes, i)?;
        let (aggregate_signature, i) = <_>::ssz_decode(bytes, i)?;

        Ok((
            SlashableVoteData {
                custody_bit_0_indices,
                custody_bit_1_indices,
                data,
                aggregate_signature,
            },
            i,
        ))
    }
}

impl TreeHash for SlashableVoteData {
    fn hash_tree_root(&self) -> Vec<u8> {
        let mut result: Vec<u8> = vec![];
        result.append(&mut self.custody_bit_0_indices.hash_tree_root());
        result.append(&mut self.custody_bit_1_indices.hash_tree_root());
        result.append(&mut self.data.hash_tree_root());
        result.append(&mut self.aggregate_signature.hash_tree_root());
        hash(&result)
    }
}

impl<T: RngCore> TestRandom<T> for SlashableVoteData {
    fn random_for_test(rng: &mut T) -> Self {
        Self {
            custody_bit_0_indices: <_>::random_for_test(rng),
            custody_bit_1_indices: <_>::random_for_test(rng),
            data: <_>::random_for_test(rng),
            aggregate_signature: <_>::random_for_test(rng),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use ssz::ssz_encode;

    #[test]
    pub fn test_ssz_round_trip() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = SlashableVoteData::random_for_test(&mut rng);

        let bytes = ssz_encode(&original);
        let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    pub fn test_hash_tree_root() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = SlashableVoteData::random_for_test(&mut rng);

        let result = original.hash_tree_root();

        assert_eq!(result.len(), 32);
        // TODO: Add further tests
        // https://github.com/sigp/lighthouse/issues/170
    }
}
<commit_msg>added is_double_vote and is_surround_vote (lighthouse-150)<commit_after>use super::AttestationData;
use crate::spec::ChainSpec;
use crate::test_utils::TestRandom;
use bls::AggregateSignature;
use rand::RngCore;
use serde_derive::Serialize;
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};

#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct SlashableVoteData {
    pub custody_bit_0_indices: Vec<u32>,
    pub custody_bit_1_indices: Vec<u32>,
    pub data: AttestationData,
    pub aggregate_signature: AggregateSignature,
}

impl SlashableVoteData {
    pub fn is_double_vote(&self, other: &SlashableVoteData, spec: &ChainSpec) -> bool {
        self.data.slot.epoch(spec.epoch_length) == other.data.slot.epoch(spec.epoch_length)
    }

    pub fn is_surround_vote(&self, other: &SlashableVoteData, spec: &ChainSpec) -> bool {
        let source_epoch_1 = self.data.justified_epoch;
        let source_epoch_2 = other.data.justified_epoch;
        let target_epoch_1 = self.data.slot.epoch(spec.epoch_length);
        let target_epoch_2 = other.data.slot.epoch(spec.epoch_length);

        (source_epoch_1 < source_epoch_2) && (target_epoch_2 < target_epoch_1)
    }
}

impl Encodable for SlashableVoteData {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.custody_bit_0_indices);
        s.append_vec(&self.custody_bit_1_indices);
        s.append(&self.data);
        s.append(&self.aggregate_signature);
    }
}

impl Decodable for SlashableVoteData {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (custody_bit_0_indices, i) = <_>::ssz_decode(bytes, i)?;
        let (custody_bit_1_indices, i) = <_>::ssz_decode(bytes, i)?;
        let (data, i) = <_>::ssz_decode(bytes, i)?;
        let (aggregate_signature, i) = <_>::ssz_decode(bytes, i)?;

        Ok((
            SlashableVoteData {
                custody_bit_0_indices,
                custody_bit_1_indices,
                data,
                aggregate_signature,
            },
            i,
        ))
    }
}

impl TreeHash for SlashableVoteData {
    fn hash_tree_root(&self) -> Vec<u8> {
        let mut result: Vec<u8> = vec![];
        result.append(&mut self.custody_bit_0_indices.hash_tree_root());
        result.append(&mut self.custody_bit_1_indices.hash_tree_root());
        result.append(&mut self.data.hash_tree_root());
        result.append(&mut self.aggregate_signature.hash_tree_root());
        hash(&result)
    }
}

impl<T: RngCore> TestRandom<T> for SlashableVoteData {
    fn random_for_test(rng: &mut T) -> Self {
        Self {
            custody_bit_0_indices: <_>::random_for_test(rng),
            custody_bit_1_indices: <_>::random_for_test(rng),
            data: <_>::random_for_test(rng),
            aggregate_signature: <_>::random_for_test(rng),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::slot_epoch_height::{Epoch, Slot};
    use crate::spec::ChainSpec;
    use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use ssz::ssz_encode;

    #[test]
    pub fn test_is_double_vote_true() {
        let spec = ChainSpec::foundation();
        let slashable_vote_first = create_slashable_vote_data(1, 1, &spec);
        let slashable_vote_second = create_slashable_vote_data(1, 1, &spec);

        assert_eq!(
            slashable_vote_first.is_double_vote(&slashable_vote_second, &spec),
            true
        )
    }

    #[test]
    pub fn test_is_double_vote_false() {
        let spec = ChainSpec::foundation();
        let slashable_vote_first = create_slashable_vote_data(1, 1, &spec);
        let slashable_vote_second = create_slashable_vote_data(2, 1, &spec);

        assert_eq!(
            slashable_vote_first.is_double_vote(&slashable_vote_second, &spec),
            false
        );
    }

    #[test]
    pub fn test_is_surround_vote_true() {
        let spec = ChainSpec::foundation();
        let slashable_vote_first = create_slashable_vote_data(2, 1, &spec);
        let slashable_vote_second = create_slashable_vote_data(1, 2, &spec);

        assert_eq!(
            slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
            true
        );
    }

    #[test]
    pub fn test_is_surround_vote_false_source_epoch_fails() {
        let spec = ChainSpec::foundation();
        let slashable_vote_first = create_slashable_vote_data(2, 2, &spec);
        let slashable_vote_second = create_slashable_vote_data(1, 1, &spec);

        assert_eq!(
            slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
            false
        );
    }

    #[test]
    pub fn test_is_surround_vote_false_target_epoch_fails() {
        let spec = ChainSpec::foundation();
        let slashable_vote_first = create_slashable_vote_data(1, 1, &spec);
        let slashable_vote_second = create_slashable_vote_data(2, 2, &spec);

        assert_eq!(
            slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
            false
        );
    }

    #[test]
    pub fn test_ssz_round_trip() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = SlashableVoteData::random_for_test(&mut rng);

        let bytes = ssz_encode(&original);
        let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    pub fn test_hash_tree_root() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = SlashableVoteData::random_for_test(&mut rng);

        let result = original.hash_tree_root();

        assert_eq!(result.len(), 32);
        // TODO: Add further tests
        // https://github.com/sigp/lighthouse/issues/170
    }

    fn create_slashable_vote_data(
        slot_factor: u64,
        justified_epoch: u64,
        spec: &ChainSpec,
    ) -> SlashableVoteData {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let mut slashable_vote = SlashableVoteData::random_for_test(&mut rng);

        slashable_vote.data.slot = Slot::new(slot_factor * spec.epoch_length);
        slashable_vote.data.justified_epoch = Epoch::new(justified_epoch);
        slashable_vote
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test

use crate::io::Write;
use core::sync::atomic::{AtomicUsize, Ordering};

// runtime features
pub(super) mod panic;
mod reloc;

// library features
pub mod mem;
pub mod thread;
pub mod tls;
#[macro_use]
pub mod usercalls;

#[cfg(not(test))]
global_asm!(include_str!("entry.S"));

#[cfg(not(test))]
#[no_mangle]
unsafe extern "C" fn tcs_init(secondary: bool) {
    // Be very careful when changing this code: it runs before the binary has been
    // relocated. Any indirect accesses to symbols will likely fail.
    const UNINIT: usize = 0;
    const BUSY: usize = 1;
    const DONE: usize = 2;
    // Three-state spin-lock
    static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);

    if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
        rtabort!("Entered secondary TCS before main TCS!")
    }

    // Try to atomically swap UNINIT with BUSY. The returned state can be:
    match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
        // This thread just obtained the lock and other threads will observe BUSY
        UNINIT => {
            reloc::relocate_elf_rela();
            RELOC_STATE.store(DONE, Ordering::Release);
        }
        // We need to wait until the initialization is done.
        BUSY => {
            while RELOC_STATE.load(Ordering::Acquire) == BUSY {
                core::arch::x86_64::_mm_pause()
            }
        }
        // Initialization is done.
        DONE => {}
        _ => unreachable!(),
    }
}

// FIXME: this item should only exist if this is linked into an executable
// (main function exists). If this is a library, the crate author should be
// able to specify this
#[cfg(not(test))]
#[no_mangle]
#[allow(improper_ctypes_definitions)]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
    // FIXME: how to support TLS in library mode?
    let tls = Box::new(tls::Tls::new());
    let _tls_guard = unsafe { tls.activate() };

    if secondary {
        super::thread::Thread::entry();

        (0, 0)
    } else {
        extern "C" {
            fn main(argc: isize, argv: *const *const u8) -> isize;
        }

        // check entry is being called according to ABI
        rtassert!(p3 == 0);
        rtassert!(p4 == 0);
        rtassert!(p5 == 0);

        unsafe {
            // The actual types of these arguments are `p1: *const Arg, p2:
            // usize`. We can't currently customize the argument list of Rust's
            // main function, so we pass these in as the standard pointer-sized
            // values in `argc` and `argv`.
            let ret = main(p2 as _, p1 as _);
            exit_with_code(ret)
        }
    }
}

pub(super) fn exit_with_code(code: isize) -> ! {
    if code != 0 {
        if let Some(mut out) = panic::SgxPanicOutput::new() {
            let _ = write!(out, "Exited with status code {}", code);
        }
    }
    usercalls::exit(code != 0);
}

#[cfg(not(test))]
#[no_mangle]
extern "C" fn abort_reentry() -> ! {
    usercalls::exit(false)
}
<commit_msg>Rollup merge of #73866 - Goirad:fix-entry-improper-ctypes, r=davidtwco<commit_after>#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test

use crate::io::Write;
use core::sync::atomic::{AtomicUsize, Ordering};

// runtime features
pub(super) mod panic;
mod reloc;

// library features
pub mod mem;
pub mod thread;
pub mod tls;
#[macro_use]
pub mod usercalls;

#[cfg(not(test))]
global_asm!(include_str!("entry.S"));

#[repr(C)]
struct EntryReturn(u64, u64);

#[cfg(not(test))]
#[no_mangle]
unsafe extern "C" fn tcs_init(secondary: bool) {
    // Be very careful when changing this code: it runs before the binary has been
    // relocated. Any indirect accesses to symbols will likely fail.
    const UNINIT: usize = 0;
    const BUSY: usize = 1;
    const DONE: usize = 2;
    // Three-state spin-lock
    static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);

    if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
        rtabort!("Entered secondary TCS before main TCS!")
    }

    // Try to atomically swap UNINIT with BUSY. The returned state can be:
    match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
        // This thread just obtained the lock and other threads will observe BUSY
        UNINIT => {
            reloc::relocate_elf_rela();
            RELOC_STATE.store(DONE, Ordering::Release);
        }
        // We need to wait until the initialization is done.
        BUSY => {
            while RELOC_STATE.load(Ordering::Acquire) == BUSY {
                core::arch::x86_64::_mm_pause()
            }
        }
        // Initialization is done.
        DONE => {}
        _ => unreachable!(),
    }
}

// FIXME: this item should only exist if this is linked into an executable
// (main function exists). If this is a library, the crate author should be
// able to specify this
#[cfg(not(test))]
#[no_mangle]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
    // FIXME: how to support TLS in library mode?
    let tls = Box::new(tls::Tls::new());
    let _tls_guard = unsafe { tls.activate() };

    if secondary {
        super::thread::Thread::entry();

        EntryReturn(0, 0)
    } else {
        extern "C" {
            fn main(argc: isize, argv: *const *const u8) -> isize;
        }

        // check entry is being called according to ABI
        rtassert!(p3 == 0);
        rtassert!(p4 == 0);
        rtassert!(p5 == 0);

        unsafe {
            // The actual types of these arguments are `p1: *const Arg, p2:
            // usize`. We can't currently customize the argument list of Rust's
            // main function, so we pass these in as the standard pointer-sized
            // values in `argc` and `argv`.
            let ret = main(p2 as _, p1 as _);
            exit_with_code(ret)
        }
    }
}

pub(super) fn exit_with_code(code: isize) -> ! {
    if code != 0 {
        if let Some(mut out) = panic::SgxPanicOutput::new() {
            let _ = write!(out, "Exited with status code {}", code);
        }
    }
    usercalls::exit(code != 0);
}

#[cfg(not(test))]
#[no_mangle]
extern "C" fn abort_reentry() -> ! {
    usercalls::exit(false)
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use hex::FromHexError;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
                .to_owned()
        }
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot".to_string();
        if !rustc_args.contains(&sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag);
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<commit_msg>avoid unnecessary allocation<commit_after>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use hex::FromHexError;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
                .to_owned()
        }
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot";
        if !rustc_args.iter().any(|e| e == sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag.to_owned());
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::{stderr, Read, Write};
use std::process;
use std::str;

fn main() {
    if let Some(url) = env::args().nth(1) {
        let (scheme, reference) = url.split_at(url.find(':').unwrap_or(0));
        if scheme == "http" {
            let mut parts = reference.split('/').skip(2); //skip first two slashes
            let remote = parts.next().unwrap_or("");
            let path = parts.next().unwrap_or("/");

            let mut remote_parts = remote.split(':');
            let host = remote_parts.next().unwrap_or("127.0.0.1");
            let port = remote_parts.next().unwrap_or("80");

            let tcp = format!("tcp:{}:{}", host, port);
            write!(stderr(), "{}\n", tcp).unwrap();

            let mut stream = File::open(tcp).unwrap();
            write!(stream, "GET {} HTTP/1.0\r\n\r\n", path).unwrap();
            stream.flush().unwrap();

            let mut bytes = [0; 65536];
            let count = stream.read(&mut bytes).unwrap();

            println!("{}", unsafe { str::from_utf8_unchecked(&bytes[.. count]) });
        } else {
            write!(stderr(), "wget: unknown scheme '{}'\n", scheme).unwrap();
            process::exit(1);
        }
    } else {
        write!(stderr(), "wget: http://host:port/path\n").unwrap();
        process::exit(1);
    }
}
<commit_msg>Fix slice index issue<commit_after>use std::env;
use std::fs::File;
use std::io::{stderr, Read, Write};
use std::process;
use std::str;

fn main() {
    if let Some(url) = env::args().nth(1) {
        let (scheme, reference) = url.split_at(url.find(':').unwrap_or(0));
        if scheme == "http" {
            let mut parts = reference.split('/').skip(2); //skip first two slashes
            let remote = parts.next().unwrap_or("");
            let path = parts.next().unwrap_or("/");

            let mut remote_parts = remote.split(':');
            let host = remote_parts.next().unwrap_or("127.0.0.1");
            let port = remote_parts.next().unwrap_or("80");

            let tcp = format!("tcp:{}:{}", host, port);
            let mut stream = File::open(tcp).unwrap();

            let request = format!("GET {} HTTP/1.0\r\n\r\n", path);
            stream.write(request.as_bytes()).unwrap();
            stream.flush().unwrap();

            let mut bytes = [0; 8192];
            let count = stream.read(&mut bytes).unwrap();
            println!("{}", unsafe { str::from_utf8_unchecked(&bytes[.. count]) });
        } else {
            write!(stderr(), "wget: unknown scheme '{}'\n", scheme).unwrap();
            process::exit(1);
        }
    } else {
        write!(stderr(), "wget: http://host:port/path\n").unwrap();
        process::exit(1);
    }
}
<|endoftext|>