<commit_before>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;

use common;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;
use glium::Surface;
use self::nalgebra::{Matrix4, PerspectiveMatrix3};

use common::{Scene, Vertex8f32};
implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub modelview_matrix_array: [[f32; 4]; 4],
	pub program: Program,
	pub projection_matrix: Matrix4<f32>,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> = Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		if scene.shaders.len() == 0 {
			panic!("No shaders loaded");
		}

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d = glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		// Load the first shader in the database by default
		// TODO: load from config settings table?
		let shader_index = 0;

		// println!("Using glsl version {}", glsl_version);

		let program: Program = program!(display,
			/*
				110 => {
					vertex: &scene.shaders[shader_index].vertex_source_110,
					fragment: &scene.shaders[shader_index].fragment_source_110,
				},
				120 => {
					vertex: &scene.shaders[shader_index].vertex_source_120,
					fragment: &scene.shaders[shader_index].fragment_source_120,
				},
				130 => {
					vertex: &scene.shaders[shader_index].vertex_source_130,
					fragment: &scene.shaders[shader_index].fragment_source_130,
				},
				*/
				140 => {
					vertex: &scene.shaders[shader_index].vertex_source_140,
					fragment: &scene.shaders[shader_index].fragment_source_140,
				},
				/*
				150 => {
					vertex: &scene.shaders[shader_index].vertex_source_150,
					fragment: &scene.shaders[shader_index].fragment_source_150,
				},
				300 => {
					vertex: &scene.shaders[shader_index].vertex_source_300,
					fragment: &scene.shaders[shader_index].fragment_source_300,
				},
				330 => {
					vertex: &scene.shaders[shader_index].vertex_source_330,
					fragment: &scene.shaders[shader_index].fragment_source_330,
				},
				400 => {
					vertex: &scene.shaders[shader_index].vertex_source_400,
					fragment: &scene.shaders[shader_index].fragment_source_400,
				},
				410 => {
					vertex: &scene.shaders[shader_index].vertex_source_410,
					fragment: &scene.shaders[shader_index].fragment_source_410,
				},
				420 => {
					vertex: &scene.shaders[shader_index].vertex_source_420,
					fragment: &scene.shaders[shader_index].fragment_source_420,
				},
				430 => {
					vertex: &scene.shaders[shader_index].vertex_source_430,
					fragment: &scene.shaders[shader_index].fragment_source_430,
				},
				100 es => {
					vertex: &scene.shaders[shader_index].vertex_source_100es,
					fragment: &scene.shaders[shader_index].fragment_source_100es,
				},
				300 es => {
					vertex: &scene.shaders[shader_index].vertex_source_300es,
					fragment: &scene.shaders[shader_index].fragment_source_300es,
				}, */
			)
			.unwrap();

		// Shader compilation no longer required
		display.release_shader_compiler();

		// Get the screen width and height in pixels
		let screen_width: u32;
		let screen_height: u32;
		match display.get_window() {
			Some(window) =>  {
				let pixel_dimensions: (u32,u32) = window.get_inner_size_pixels().unwrap();
				screen_width = pixel_dimensions.0;
				screen_height = pixel_dimensions.1;
			},
			None => {
				panic!("Error retrieving window when querying display size.");
			}
		}

		// Set up camera
		let projection_matrix = PerspectiveMatrix3::new(screen_width as f32 / screen_height as f32,
		                                          45.0,
		                                          0.1,
		                                          1000.0);
		let projection_matrix_array: Matrix4<f32> = projection_matrix.to_matrix();

		let modelview_matrix_array = [[1.0f32, -0.0f32, -0.0f32, 0.0f32],
		                          [0.0f32, 1.0f32, -0.0f32, 0.0f32],
		                          [0.0f32, 0.0f32, 1.0f32, 0.0f32],
		                          [-5.0f32, -3.0f32, -12.0f32, 1.0f32]];
		Renderer {
			index_buffer: index_buffer,
			modelview_matrix_array: modelview_matrix_array,
			program: program,
			projection_matrix: projection_matrix_array,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn render(&self, display: &GlutinFacade) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color(0.0, 0.0, 0.0, 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *self.projection_matrix.as_ref(),
				modelview: self.modelview_matrix_array,
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
			};

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				&self.program,
				&uniforms,
				&Default::default())
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<commit_msg>line-wrapping format changes<commit_after>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;

use common;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;
use glium::Surface;
use self::nalgebra::{Matrix4, PerspectiveMatrix3};

use common::{Scene, Vertex8f32};
implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub modelview_matrix_array: [[f32; 4]; 4],
	pub program: Program,
	pub projection_matrix: Matrix4<f32>,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> =
			Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		if scene.shaders.len() == 0 {
			panic!("No shaders loaded");
		}

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d =
				glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		// Load the first shader in the database by default
		// TODO: load from config settings table?
		let shader_index = 0;

		// println!("Using glsl version {}", glsl_version);

		let program: Program = program!(display,
			/*
				110 => {
					vertex: &scene.shaders[shader_index].vertex_source_110,
					fragment: &scene.shaders[shader_index].fragment_source_110,
				},
				120 => {
					vertex: &scene.shaders[shader_index].vertex_source_120,
					fragment: &scene.shaders[shader_index].fragment_source_120,
				},
				130 => {
					vertex: &scene.shaders[shader_index].vertex_source_130,
					fragment: &scene.shaders[shader_index].fragment_source_130,
				},
				*/
				140 => {
					vertex: &scene.shaders[shader_index].vertex_source_140,
					fragment: &scene.shaders[shader_index].fragment_source_140,
				},
				/*
				150 => {
					vertex: &scene.shaders[shader_index].vertex_source_150,
					fragment: &scene.shaders[shader_index].fragment_source_150,
				},
				300 => {
					vertex: &scene.shaders[shader_index].vertex_source_300,
					fragment: &scene.shaders[shader_index].fragment_source_300,
				},
				330 => {
					vertex: &scene.shaders[shader_index].vertex_source_330,
					fragment: &scene.shaders[shader_index].fragment_source_330,
				},
				400 => {
					vertex: &scene.shaders[shader_index].vertex_source_400,
					fragment: &scene.shaders[shader_index].fragment_source_400,
				},
				410 => {
					vertex: &scene.shaders[shader_index].vertex_source_410,
					fragment: &scene.shaders[shader_index].fragment_source_410,
				},
				420 => {
					vertex: &scene.shaders[shader_index].vertex_source_420,
					fragment: &scene.shaders[shader_index].fragment_source_420,
				},
				430 => {
					vertex: &scene.shaders[shader_index].vertex_source_430,
					fragment: &scene.shaders[shader_index].fragment_source_430,
				},
				100 es => {
					vertex: &scene.shaders[shader_index].vertex_source_100es,
					fragment: &scene.shaders[shader_index].fragment_source_100es,
				},
				300 es => {
					vertex: &scene.shaders[shader_index].vertex_source_300es,
					fragment: &scene.shaders[shader_index].fragment_source_300es,
				}, */
			)
			.unwrap();

		// Shader compilation no longer required
		display.release_shader_compiler();

		// Get the screen width and height in pixels
		let screen_width: u32;
		let screen_height: u32;
		match display.get_window() {
			Some(window) =>  {
				let pixel_dimensions: (u32,u32) = window.get_inner_size_pixels().unwrap();
				screen_width = pixel_dimensions.0;
				screen_height = pixel_dimensions.1;
			},
			None => {
				panic!("Error retrieving window when querying display size.");
			}
		}

		// Set up camera
		let projection_matrix = PerspectiveMatrix3::new(screen_width as f32 / screen_height as f32,
		                                          45.0,
		                                          0.1,
		                                          1000.0);
		let projection_matrix_array: Matrix4<f32> = projection_matrix.to_matrix();

		let modelview_matrix_array = [[1.0f32, -0.0f32, -0.0f32, 0.0f32],
		                          [0.0f32, 1.0f32, -0.0f32, 0.0f32],
		                          [0.0f32, 0.0f32, 1.0f32, 0.0f32],
		                          [-5.0f32, -3.0f32, -12.0f32, 1.0f32]];
		Renderer {
			index_buffer: index_buffer,
			modelview_matrix_array: modelview_matrix_array,
			program: program,
			projection_matrix: projection_matrix_array,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn render(&self, display: &GlutinFacade) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color(0.0, 0.0, 0.0, 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *self.projection_matrix.as_ref(),
				modelview: self.modelview_matrix_array,
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
			};

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				&self.program,
				&uniforms,
				&Default::default())
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<|endoftext|>


<commit_before>use std::result::Result;

use backend::Backend;
use provider::error::Error;
use provider::error::StringError;
use provider::Output;
use provider::file::shell::ShellProvider;

#[derive(Clone, Debug)]
pub struct Unix;

impl ShellProvider for Unix {
    fn exist(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -e {}", name);
        let res = try!(b.run_command(&c));
        Ok(Output::Bool(res.success))
    }

    fn is_file(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -f {}", name);
        self.is_something(name, b, c)
    }

    fn is_directory(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -d {}", name);
        self.is_something(name, b, c)
    }

    fn is_block_device(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -b {}", name);
        self.is_something(name, b, c)
    }

    fn is_character_device(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -c {}", name);
        self.is_something(name, b, c)
    }

    fn is_pipe(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -p {}", name);
        self.is_something(name, b, c)
    }

    fn is_socket(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -S {}", name);
        self.is_something(name, b, c)
    }

    fn is_symlink(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -L {}", name);
        self.is_something(name, b, c)
    }

    fn contents(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("cat {}", name);
        let res = try!(b.run_command(&c));
        Ok(Output::Text(res.stdout))
    }

    fn box_clone(&self) -> Box<ShellProvider> {
        Box::new((*self).clone())
    }
}

impl Unix {
    pub fn is_something(&self, name: &str, b: &Backend, c: String) -> Result<Output, Error> {
        let exist = try!(self.exist(name, b));
        if !try!(Output::to_bool(exist)) {
            let e = StringError { string: format!("{} does not exist", name) };
            return Err(From::from(e));
        }

        let res = b.run_command(&c);
        let success = match res {
            Ok(r) => r.success,
            Err(_) => false,
        };
        Ok(Output::Bool(success))
    }
}
<commit_msg>file.exsit() return false when it does not exist<commit_after>use std::result::Result;

use backend::Backend;
use provider::error::Error;
use provider::error::StringError;
use provider::Output;
use provider::file::shell::ShellProvider;

#[derive(Clone, Debug)]
pub struct Unix;

impl ShellProvider for Unix {
    fn exist(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -e {}", name);
        let success = match b.run_command(&c) {
            Ok(r) => r.success,
            Err(_) => false,
        };
        Ok(Output::Bool(success))
    }

    fn is_file(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -f {}", name);
        self.is_something(name, b, c)
    }

    fn is_directory(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -d {}", name);
        self.is_something(name, b, c)
    }

    fn is_block_device(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -b {}", name);
        self.is_something(name, b, c)
    }

    fn is_character_device(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -c {}", name);
        self.is_something(name, b, c)
    }

    fn is_pipe(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -p {}", name);
        self.is_something(name, b, c)
    }

    fn is_socket(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -S {}", name);
        self.is_something(name, b, c)
    }

    fn is_symlink(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("test -L {}", name);
        self.is_something(name, b, c)
    }

    fn contents(&self, name: &str, b: &Backend) -> Result<Output, Error> {
        let c = format!("cat {}", name);
        let res = try!(b.run_command(&c));
        Ok(Output::Text(res.stdout))
    }

    fn box_clone(&self) -> Box<ShellProvider> {
        Box::new((*self).clone())
    }
}

impl Unix {
    pub fn is_something(&self, name: &str, b: &Backend, c: String) -> Result<Output, Error> {
        let exist = try!(self.exist(name, b));
        if !try!(Output::to_bool(exist)) {
            let e = StringError { string: format!("{} does not exist", name) };
            return Err(From::from(e));
        }

        let res = b.run_command(&c);
        let success = match res {
            Ok(r) => r.success,
            Err(_) => false,
        };
        Ok(Output::Bool(success))
    }
}
<|endoftext|>


<commit_before>use ClientState;
use read::read_varint;
use write::write_varint;

use std::io::{Cursor, Read, Write};
use std::marker::PhantomData;
use std::net::Shutdown;
use std::net::TcpStream;
use std::{io, time};

use netbuf::Buf;

use flate2::Compress;
use flate2::read::ZlibDecoder;
use flate2;

use openssl::symm;

/// Trait for the two enums ClientboundPacket and ServerboundPacket
pub trait Packet: Sized {
    fn deserialize<R: Read>(r: &mut R,
                            state: &ClientState)
                            -> io::Result<Self>;
    fn get_packet_name(&self) -> &str;
    fn get_clientstate(&self) -> ClientState;
    fn get_id(&self) -> i32;
    fn to_u8(&self) -> io::Result<Vec<u8>>;
}

/// Represents a single MC connection, either as client or server
pub struct Connection<I: Packet, O: Packet> {
    stream: TcpStream,
    clientstate: ClientState,
    /* The buffer for clientbound packets */
    buf: Buf,
    /* This tracks the length the next packet in the buffer.
     * If None, then we haven't received enough bytes to completely figure out
     * the packet length (usually means we haven't received anything, but MIGHT
     * also mean we haven't received the full header yet)
     *
     * If Some(x) then we need to read x bytes from the buf to get the complete
     * packet (excluding packet length header, including encryption/compression/
     * packet id header) */
    packet_len: Option<usize>,
    compression: Option<usize>,
    /* Incoming encryption cipher */
    in_encryption: Option<symm::Crypter>,
    /* Outgoing encryption cipher */
    out_encryption: Option<symm::Crypter>,
    /* When we last read something from the server. Use this to timeout the
     * connection if the connection is lost */
    last_read: time::Instant,
    in_type: PhantomData<I>,
    out_type: PhantomData<O>,
}
impl<I: Packet, O: Packet> Connection<I, O> {
    pub fn connect_tcp(host: &str, port: u16) -> io::Result<Self> {
        let conn = Connection {
            stream: TcpStream::connect(&format!("{}:{}", host, port))?,
            clientstate: ClientState::Handshake,
            buf: Buf::new(),
            packet_len: None,
            compression: None,
            in_encryption: None,
            out_encryption: None,
            last_read: time::Instant::now(),
            in_type: PhantomData,
            out_type: PhantomData,
        };
        /* Set 30 second timeout */
        conn.stream.set_read_timeout(Some(time::Duration::new(30, 0)))?;
        conn.stream.set_write_timeout(Some(time::Duration::new(30, 0)))?;
        Ok(conn)
    }

    /// Send the given packet
    pub fn send(&mut self, packet: O) -> io::Result<()> {
        let tmp = packet.to_u8()?;
        let uncompressed_length = tmp.len();
        let mut out = Vec::with_capacity(uncompressed_length);

        match self.compression {
            Some(threshold) if uncompressed_length >= threshold => {
                /* We have to copy all the data again, because we need
                 * to prefix the packet with length of the compressed data */
                let mut output = Vec::new();
                let mut compressor = Compress::new(::COMPRESSION_LEVEL, false);
                match compressor.compress(&tmp,
                                          &mut output,
                                          flate2::Flush::Sync) {
                    flate2::Status::Ok => {
                        return io_error!("Got a Status::Ok when trying to compress outgoing packet");
                    },
                    flate2::Status::BufError => {
                        return io_error!("Got a Status::BufError when trying to compress outgoing packet");
                    },
                    flate2::Status::StreamEnd => (),
                }

                write_varint(&(output.len() as i32), &mut out)?;
                write_varint(&(uncompressed_length as i32), &mut out)?;
                out.write_all(&output)?;
            },
            Some(_) => {
                /* Add 1 to the uncompressed length for the 1 byte it takes
                 * to specify no compression */
                write_varint(&((uncompressed_length + 1) as i32), &mut out)?;
                write_varint(&0, &mut out)?;
                out.write_all(&tmp)?;
            },
            None => {
                write_varint(&(uncompressed_length as i32), &mut out)?;
                out.write_all(&tmp)?;
            },
        }

        if let Some(ref mut enc) = self.out_encryption {
            let mut tmp = vec![0; out.len() + 16];
            let n = match enc.update(&out, &mut tmp) {
                Ok(x) => x,
                Err(_) => return io_error!("client::send error writing encrypted data"),
            };
            self.stream.write_all(&tmp[..n])?;
        } else {
            self.stream.write_all(&out)?;
        }

        Ok(())
    }

    /// Attempt to close this connection.
    ///
    /// All future sends and reads to this connection will fail
    pub fn close(&mut self) -> io::Result<()> {
        self.stream.shutdown(Shutdown::Both)
    }

    /// Change the client state of this connection
    pub fn set_clientstate(&mut self, new_state: ClientState) {
        self.clientstate = new_state;
    }

    /// Enable encryption with the given key.
    ///
    /// It is an error to enable encryption if encryption has already been
    /// enabled.
    pub fn enable_encryption(&mut self, key: &[u8; 16]) {
        let out_cipher =
            symm::Crypter::new(symm::Cipher::aes_128_cfb8(),
                               symm::Mode::Encrypt,
                               key,
                               Some(key))
                    .expect("client::enable_encryption error creating cipher");
        let in_cipher =
            symm::Crypter::new(symm::Cipher::aes_128_cfb8(),
                               symm::Mode::Decrypt,
                               key,
                               Some(key))
                    .expect("client::enable_encryption error creating cipher");

        self.out_encryption = Some(out_cipher);
        self.in_encryption = Some(in_cipher);
    }

    /// Enable compression.
    ///
    /// It is generally an error to enable compression if compression has
    /// already been enabled.
    pub fn enable_compression(&mut self, threshold: usize) {
        self.compression = Some(threshold);
    }

    /// Read from the TcpStream and update the incoming buffer.
    ///
    /// This is the only way to actually read from the TcpStream. Unless you
    /// know for sure you need to call this, then you do not need to call this.
    /// I.e. if you're just using client.read(), then you do not need to call
    /// this function.
    pub fn update_inbuf(&mut self) -> io::Result<()> {
        if let Some(ref mut enc) = self.in_encryption {
            let mut enc_buf = Buf::new();
            let n = enc_buf.read_from(&mut self.stream)?;
            let mut tmp = vec![0; n + 16];
            let n = match enc.update(&enc_buf[..], &mut tmp) {
                Ok(x) => x,
                Err(_) => return io_error!("connection::update_inbuf error reading encrypted data"),
            };
            self.buf.extend(&tmp[..n]);
        } else {
            let _: usize = self.buf.read_from(&mut self.stream)?;
        }
        Ok(())
    }

    /// Read a single packet from the internal buffer.
    ///
    /// This is only really useful if you want finegrained control over the
    /// processing of packets, or if you want to manually authenticate with
    /// the server. In most cases, you'll want to just call client.read().
    ///
    /// You MUST be sure that client.update_inbuf() has been called before this,
    /// this function will not attempt to read from the TcpStream, only from the
    /// internal buffer.
    pub fn read_packet(&mut self) -> io::Result<Option<I>> {
        if let None = self.packet_len {
            self.read_length()?;
        }

        let len = match self.packet_len {
            Some(x) => x,
            None => {
                if self.last_read.elapsed() > time::Duration::new(30, 0) {
                    /* If we haven't read anything for 30 seconds, timeout */
                    self.close()?;
                    return io_error!("Read timeout");
                } else {
                    return Ok(None);
                }
            },
        };

        if self.buf.len() < len {
            /* We haven't received enough yet to read the whole packet */
            if self.last_read.elapsed() > time::Duration::new(30, 0) {
                /* If we haven't read anything for 30 seconds, timeout */
                self.close()?;
                return io_error!("Read timeout");
            } else {
                return Ok(None);
            }
        } else {
            self.last_read = time::Instant::now();
        }

        let packet = {
            let data = &self.buf[..len];
            let mut r = Cursor::new(data);

            /* This is where we decompress compressed packets and decrypt
             * encrypted packets */
            match self.compression {
                Some(_) => {
                    let compressed_length = read_varint(&mut r)?;
                    if compressed_length == 0 {
                        I::deserialize(&mut r, &self.clientstate)?
                    } else {
                        let mut r = ZlibDecoder::new(r);
                        I::deserialize(&mut r, &self.clientstate)?
                    }
                },
                None => I::deserialize(&mut r, &self.clientstate)?,
            }
        };

        self.buf.consume(len);
        self.packet_len = None;

        Ok(Some(packet))
    }

    /** Tries to read the length of the next packet in the buf, and sets
     * self.packet_len accordingly. It will return Ok(()) as long as it doesn't
     * encounter any io errors, even if it doesn't read the whole length
     * (for example if the buffer is empty.) It will only consume the length
     * header from the buf if it successfully reads the entire length header */
    fn read_length(&mut self) -> io::Result<()> {
        let msb: u8 = 128; /* Only the MSB set */
        let mut i: usize = 0;

        /* The result */
        let res: usize = {
            let mut tmp = match self.buf.get(i) {
                Some(x) => x,
                None => return Ok(()),
            };

            let mut res = (tmp & (!msb)) as usize;

            /* While the previous byte had the MSB set */
            while (tmp & msb) != 0 {
                i += 1;

                /* A varint can be at most 5 bytes, remember it's nullindexed */
                if i >= 5 {
                    return io_error!("Received varint that was too long");
                }

                tmp = match self.buf.get(i) {
                    Some(x) => x,
                    None => return Ok(()),
                };

                res += ((tmp & (!msb)) as usize) << (7 * i);
            }

            res
        };

        self.packet_len = Some(res);
        /* Consume the length header as we no longer need it */
        self.buf.consume(i + 1);
        Ok(())
    }
}
<commit_msg>Update some documentation<commit_after>use ClientState;
use read::read_varint;
use write::write_varint;

use std::io::{Cursor, Read, Write};
use std::marker::PhantomData;
use std::net::Shutdown;
use std::net::TcpStream;
use std::{io, time};

use netbuf::Buf;

use flate2::Compress;
use flate2::read::ZlibDecoder;
use flate2;

use openssl::symm;

/// Trait for the two enums ClientboundPacket and ServerboundPacket
pub trait Packet: Sized {
    fn deserialize<R: Read>(r: &mut R,
                            state: &ClientState)
                            -> io::Result<Self>;
    fn get_packet_name(&self) -> &str;
    fn get_clientstate(&self) -> ClientState;
    fn get_id(&self) -> i32;
    fn to_u8(&self) -> io::Result<Vec<u8>>;
}

/// Represents a single MC connection, either as client or server
pub struct Connection<I: Packet, O: Packet> {
    stream: TcpStream,
    clientstate: ClientState,
    /* The buffer for clientbound packets */
    buf: Buf,
    /* This tracks the length the next packet in the buffer.
     * If None, then we haven't received enough bytes to completely figure out
     * the packet length (usually means we haven't received anything, but MIGHT
     * also mean we haven't received the full header yet)
     *
     * If Some(x) then we need to read x bytes from the buf to get the complete
     * packet (excluding packet length header, including encryption/compression/
     * packet id header) */
    packet_len: Option<usize>,
    compression: Option<usize>,
    /* Incoming encryption cipher */
    in_encryption: Option<symm::Crypter>,
    /* Outgoing encryption cipher */
    out_encryption: Option<symm::Crypter>,
    /* When we last read something from the server. Use this to timeout the
     * connection if the connection is lost */
    last_read: time::Instant,
    in_type: PhantomData<I>,
    out_type: PhantomData<O>,
}
impl<I: Packet, O: Packet> Connection<I, O> {
    pub fn connect_tcp(host: &str, port: u16) -> io::Result<Self> {
        let conn = Connection {
            stream: TcpStream::connect(&format!("{}:{}", host, port))?,
            clientstate: ClientState::Handshake,
            buf: Buf::new(),
            packet_len: None,
            compression: None,
            in_encryption: None,
            out_encryption: None,
            last_read: time::Instant::now(),
            in_type: PhantomData,
            out_type: PhantomData,
        };
        /* Set 30 second timeout */
        conn.stream.set_read_timeout(Some(time::Duration::new(30, 0)))?;
        conn.stream.set_write_timeout(Some(time::Duration::new(30, 0)))?;
        Ok(conn)
    }

    /// Send the given packet
    pub fn send(&mut self, packet: O) -> io::Result<()> {
        let tmp = packet.to_u8()?;
        let uncompressed_length = tmp.len();
        let mut out = Vec::with_capacity(uncompressed_length);

        match self.compression {
            /* Compression is enabled, and the packet length is over the
             * threshold, thus compress the packet */
            Some(threshold) if uncompressed_length >= threshold => {
                /* We have to copy all the data again, because we need
                 * to prefix the packet with length of the compressed data */
                let mut output = Vec::new();
                let mut compressor = Compress::new(::COMPRESSION_LEVEL, false);
                match compressor.compress(&tmp,
                                          &mut output,
                                          flate2::Flush::Sync) {
                    flate2::Status::Ok => {
                        return io_error!("Got a Status::Ok when trying to compress outgoing packet");
                    },
                    flate2::Status::BufError => {
                        return io_error!("Got a Status::BufError when trying to compress outgoing packet");
                    },
                    flate2::Status::StreamEnd => (),
                }

                write_varint(&(output.len() as i32), &mut out)?;
                write_varint(&(uncompressed_length as i32), &mut out)?;
                out.write_all(&output)?;
            },
            /* Compression is enabled, but the packet length is not over the
             * threshold, thus we don't compress the packet */
            Some(_) => {
                /* Add 1 to the uncompressed length for the 1 byte it takes
                 * to specify no compression */
                write_varint(&((uncompressed_length + 1) as i32), &mut out)?;
                write_varint(&0, &mut out)?;
                out.write_all(&tmp)?;
            },
            /* Compression is not enabled */
            None => {
                write_varint(&(uncompressed_length as i32), &mut out)?;
                out.write_all(&tmp)?;
            },
        }

        if let Some(ref mut enc) = self.out_encryption {
            let mut tmp = vec![0; out.len() + 16];
            let n = match enc.update(&out, &mut tmp) {
                Ok(x) => x,
                Err(_) => return io_error!("client::send error writing encrypted data"),
            };
            self.stream.write_all(&tmp[..n])?;
        } else {
            self.stream.write_all(&out)?;
        }

        Ok(())
    }

    /// Attempt to close this connection.
    ///
    /// All future sends and reads to this connection will fail
    pub fn close(&mut self) -> io::Result<()> {
        self.stream.shutdown(Shutdown::Both)
    }

    /// Change the client state of this connection
    pub fn set_clientstate(&mut self, new_state: ClientState) {
        self.clientstate = new_state;
    }

    /// Enable encryption with the given key.
    ///
    /// It is an error to enable encryption if encryption has already been
    /// enabled.
    pub fn enable_encryption(&mut self, key: &[u8; 16]) {
        let out_cipher =
            symm::Crypter::new(symm::Cipher::aes_128_cfb8(),
                               symm::Mode::Encrypt,
                               key,
                               Some(key))
                    .expect("client::enable_encryption error creating cipher");
        let in_cipher =
            symm::Crypter::new(symm::Cipher::aes_128_cfb8(),
                               symm::Mode::Decrypt,
                               key,
                               Some(key))
                    .expect("client::enable_encryption error creating cipher");

        self.out_encryption = Some(out_cipher);
        self.in_encryption = Some(in_cipher);
    }

    /// Enable compression.
    ///
    /// It is generally an error to enable compression if compression has
    /// already been enabled.
    pub fn enable_compression(&mut self, threshold: usize) {
        self.compression = Some(threshold);
    }

    /// Read from the TcpStream and update the incoming buffer.
    ///
    /// This is the only way to actually read from the TcpStream. Unless you
    /// know for sure you need to call this, then you do not need to call this.
    /// I.e. if you're just using client.read(), then you do not need to call
    /// this function.
    pub fn update_inbuf(&mut self) -> io::Result<()> {
        if let Some(ref mut enc) = self.in_encryption {
            let mut enc_buf = Buf::new();
            let n = enc_buf.read_from(&mut self.stream)?;
            let mut tmp = vec![0; n + 16];
            let n = match enc.update(&enc_buf[..], &mut tmp) {
                Ok(x) => x,
                Err(_) => return io_error!("connection::update_inbuf error reading encrypted data"),
            };
            self.buf.extend(&tmp[..n]);
        } else {
            let _: usize = self.buf.read_from(&mut self.stream)?;
        }
        Ok(())
    }

    /// Read a single packet from the internal buffer.
    ///
    /// This is only really useful if you want finegrained control over the
    /// processing of packets, or if you want to manually authenticate with
    /// the server. In most cases, you'll want to just call client.read().
    ///
    /// You MUST be sure that client.update_inbuf() has been called before this,
    /// this function will not attempt to read from the TcpStream, only from the
    /// internal buffer.
    pub fn read_packet(&mut self) -> io::Result<Option<I>> {
        if let None = self.packet_len {
            self.read_length()?;
        }

        let len = match self.packet_len {
            Some(x) => x,
            None => {
                if self.last_read.elapsed() > time::Duration::new(30, 0) {
                    /* If we haven't read anything for 30 seconds, timeout */
                    self.close()?;
                    return io_error!("Read timeout");
                } else {
                    return Ok(None);
                }
            },
        };

        if self.buf.len() < len {
            /* We haven't received enough yet to read the whole packet */
            if self.last_read.elapsed() > time::Duration::new(30, 0) {
                /* If we haven't read anything for 30 seconds, timeout */
                self.close()?;
                return io_error!("Read timeout");
            } else {
                return Ok(None);
            }
        } else {
            self.last_read = time::Instant::now();
        }

        let packet = {
            let data = &self.buf[..len];
            let mut r = Cursor::new(data);

            match self.compression {
                Some(_) => {
                    let compressed_length = read_varint(&mut r)?;
                    if compressed_length == 0 {
                        /* Compression is enabled, but the given packet
                         * is not compressed */
                        I::deserialize(&mut r, &self.clientstate)?
                    } else {
                        /* Compression is enabled, and the given packet
                         * is compressed */
                        let mut r = ZlibDecoder::new(r);
                        I::deserialize(&mut r, &self.clientstate)?
                    }
                },
                /* Compression is not enabled */
                None => I::deserialize(&mut r, &self.clientstate)?,
            }
        };

        self.buf.consume(len);
        self.packet_len = None;

        Ok(Some(packet))
    }

    /** Tries to read the length of the next packet in the buf, and sets
     * self.packet_len accordingly. It will return Ok(()) as long as it doesn't
     * encounter any io errors, even if it doesn't read the whole length
     * (for example if the buffer is empty.) It will only consume the length
     * header from the buf if it successfully reads the entire length header */
    fn read_length(&mut self) -> io::Result<()> {
        let msb: u8 = 128; /* Only the MSB set */
        let mut i: usize = 0;

        /* The result */
        let res: usize = {
            let mut tmp = match self.buf.get(i) {
                Some(x) => x,
                None => return Ok(()),
            };

            let mut res = (tmp & (!msb)) as usize;

            /* While the previous byte had the MSB set */
            while (tmp & msb) != 0 {
                i += 1;

                /* A varint can be at most 5 bytes, remember it's nullindexed */
                if i >= 5 {
                    return io_error!("Received varint that was too long");
                }

                tmp = match self.buf.get(i) {
                    Some(x) => x,
                    None => return Ok(()),
                };

                res += ((tmp & (!msb)) as usize) << (7 * i);
            }

            res
        };

        self.packet_len = Some(res);
        /* Consume the length header as we no longer need it */
        self.buf.consume(i + 1);
        Ok(())
    }
}
<|endoftext|>


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

use sodiumoxide::crypto::stream;
use hash::Hash;
use hash::tree::HashRef;
use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

pub struct PlainText(Vec<u8>);
pub struct CipherText(Vec<u8>);
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod desc {
    pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                               NONCEBYTES, Nonce};

    pub fn fixed_key_overhead() -> usize {
        // MAC for the plaintext being sealed + the footer.
        MACBYTES + footer_cipher_bytes()
    }

    pub fn footer_plain_bytes() -> usize {
        // Footer contains a Nonce and a LittleEndian u64.
        NONCEBYTES + 8
    }

    pub fn footer_cipher_bytes() -> usize {
        footer_plain_bytes() + MACBYTES
    }

    pub fn static_nonce() -> Nonce {
        Nonce::from_slice(&[255; NONCEBYTES]).unwrap()
    }
}

mod imp {
    pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
}

fn wrap_key(key: desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn from_vec(mut bytes: &mut Vec<u8>) -> PlainText {
        let mut pt = PlainText(Vec::with_capacity(bytes.len()));
        pt.0.append(&mut bytes);
        pt
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn to_ciphertext(&self, nonce: &desc::Nonce, key: &desc::Key) -> CipherText {
        CipherText(imp::seal(&self.0, &nonce, &key))
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
}

impl CipherText {
    pub fn new(ct: Vec<u8>) -> CipherText {
        CipherText(ct)
    }
    pub fn from(mut other_ct: &mut CipherText) -> CipherText {
        let mut ct = CipherText::new(Vec::with_capacity(other_ct.len()));
        ct.append(&mut other_ct);
        ct
    }
    pub fn append(&mut self, other: &mut CipherText) {
        self.0.append(&mut other.0);
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn empty_into(&mut self, out: &mut CipherText) {
        out.0.append(&mut self.0)
    }
    pub fn random_pad_upto(&mut self, final_size: usize) {
        let size = self.len();
        if final_size > size {
            self.0.resize(final_size, 0);
            let key = stream::salsa20::gen_key();
            let nonce = stream::salsa20::gen_nonce();
            stream::salsa20::stream_xor_inplace(&mut self.0[size..], &nonce, &key);
        }
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
    pub fn as_ref(&self) -> CipherTextRef {
        CipherTextRef(&self.0[..])
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self, len: usize) -> (CipherTextRef<'a>, CipherTextRef<'a>) {
        assert!(self.len() >= len);
        (self.slice(0, self.len() - len), self.slice(self.len() - len, self.len()))
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn to_plaintext(&self, nonce: &desc::Nonce, key: &desc::Key) -> Result<PlainText, ()> {
        Ok(PlainText(try!(imp::open(&self.0, &nonce, &key))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainText) -> CipherText {
        // TODO(jos): WIP: Plug in encryption/crypto here.
        // Update cref with key.
        let key = imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let ct = pt.to_ciphertext(&desc::static_nonce(), &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash, cref: &ChunkRef, ct: CipherTextRef) -> Result<PlainText, ()> {
        assert!(ct.len() >= cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) => {
                Ok(try!(ct.to_plaintext(&desc::static_nonce(), &key)))
            }
            _ => panic!("Unknown blob key type"),
        }
    }
}

pub struct FixedKey {
    key: desc::Key,
}

impl FixedKey {
    pub fn new(key: desc::Key) -> FixedKey {
        FixedKey { key: key }
    }

    pub fn tie_knot(&self, pt: PlainText) -> CipherText {
        let nonce = imp::gen_nonce();
        let mut ct = pt.to_ciphertext(&nonce, &self.key);

        // Build footer from nonce and serialized ciphertext length.
        let ct_len = ct.len();
        let mut foot_pt = PlainText(nonce.as_ref().to_owned());
        foot_pt.0.write_u64::<LittleEndian>(ct_len as u64).unwrap();
        assert_eq!(foot_pt.len(), desc::footer_plain_bytes());

        // Tie the knot by sealing the nonce and ciphertext length.
        assert!(ct_len > desc::NONCEBYTES);
        let nonce = desc::Nonce::from_slice(&ct.0[ct_len - desc::NONCEBYTES..]).unwrap();
        ct.append(&mut foot_pt.to_ciphertext(&nonce, &self.key));

        // Return complete ciphertext.
        ct
    }

    fn untie_knot<'a>(&self, ct: CipherTextRef<'a>) -> Result<(CipherTextRef<'a>, PlainText), ()> {
        // Partial untie of knot: recover footer with nonce and ciphertext length.
        let foot_size = desc::footer_cipher_bytes();
        let (rest, foot_ct) = ct.split_from_right(foot_size);
        let nonce = desc::Nonce::from_slice(&rest.as_bytes()[rest.len() - desc::NONCEBYTES..])
            .unwrap();
        let foot_pt = try!(foot_ct.to_plaintext(&nonce, &self.key));

        let nonce = desc::Nonce::from_slice(&foot_pt.as_bytes()[..desc::NONCEBYTES]).unwrap();
        let ct_len = (&foot_pt.as_bytes()[desc::NONCEBYTES..]).read_u64::<LittleEndian>().unwrap();

        // Complete untie: recover plaintext.
        let (rest, ct) = rest.split_from_right(ct_len as usize);
        Ok((rest, try!(ct.to_plaintext(&nonce, &self.key))))
    }

    pub fn seal(&self, pt: PlainText) -> CipherText {
        // Seal with fixed key.
        self.tie_knot(pt)
    }

    pub fn unseal<'a, 'b>(&'a self,
                          ct: CipherTextRef<'b>)
                          -> Result<(CipherTextRef<'b>, PlainText), ()> {
        // Unseal with fixed key.
        self.untie_knot(ct)
    }
}
<commit_msg>Replace static nonce with data hash.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use sodiumoxide::crypto::stream;
use hash::Hash;
use hash::tree::HashRef;
use blob::{ChunkRef, Key};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

pub struct PlainText(Vec<u8>);
pub struct CipherText(Vec<u8>);
pub struct CipherTextRef<'a>(&'a [u8]);

pub mod desc {
    pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{KEYBYTES, Key, MACBYTES,
                                                               NONCEBYTES, Nonce};

    pub fn fixed_key_overhead() -> usize {
        // MAC for the plaintext being sealed + the footer.
        MACBYTES + footer_cipher_bytes()
    }

    pub fn footer_plain_bytes() -> usize {
        // Footer contains a Nonce and a LittleEndian u64.
        NONCEBYTES + 8
    }

    pub fn footer_cipher_bytes() -> usize {
        footer_plain_bytes() + MACBYTES
    }
}

mod imp {
    pub use sodiumoxide::crypto::secretbox::xsalsa20poly1305::{gen_key, gen_nonce, open, seal};
}

fn wrap_key(key: desc::Key) -> Key {
    Key::XSalsa20Poly1305(key)
}

impl PlainText {
    pub fn new(bytes: Vec<u8>) -> PlainText {
        PlainText(bytes)
    }
    pub fn from_vec(mut bytes: &mut Vec<u8>) -> PlainText {
        let mut pt = PlainText(Vec::with_capacity(bytes.len()));
        pt.0.append(&mut bytes);
        pt
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn to_ciphertext(&self, nonce: &desc::Nonce, key: &desc::Key) -> CipherText {
        CipherText(imp::seal(&self.0, &nonce, &key))
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
}

impl CipherText {
    pub fn new(ct: Vec<u8>) -> CipherText {
        CipherText(ct)
    }
    pub fn from(mut other_ct: &mut CipherText) -> CipherText {
        let mut ct = CipherText::new(Vec::with_capacity(other_ct.len()));
        ct.append(&mut other_ct);
        ct
    }
    pub fn append(&mut self, other: &mut CipherText) {
        self.0.append(&mut other.0);
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn empty_into(&mut self, out: &mut CipherText) {
        out.0.append(&mut self.0)
    }
    pub fn random_pad_upto(&mut self, final_size: usize) {
        let size = self.len();
        if final_size > size {
            self.0.resize(final_size, 0);
            let key = stream::salsa20::gen_key();
            let nonce = stream::salsa20::gen_nonce();
            stream::salsa20::stream_xor_inplace(&mut self.0[size..], &nonce, &key);
        }
    }
    pub fn into_vec(self) -> Vec<u8> {
        self.0
    }
    pub fn as_ref(&self) -> CipherTextRef {
        CipherTextRef(&self.0[..])
    }
}

impl<'a> CipherTextRef<'a> {
    pub fn new(bytes: &'a [u8]) -> CipherTextRef<'a> {
        CipherTextRef(bytes)
    }
    pub fn slice(&self, from: usize, to: usize) -> CipherTextRef<'a> {
        CipherTextRef(&self.0[from..to])
    }
    pub fn len(&self) -> usize {
        self.0.len()
    }
    pub fn split_from_right(&self, len: usize) -> (CipherTextRef<'a>, CipherTextRef<'a>) {
        assert!(self.len() >= len);
        (self.slice(0, self.len() - len), self.slice(self.len() - len, self.len()))
    }
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }
    pub fn to_plaintext(&self, nonce: &desc::Nonce, key: &desc::Key) -> Result<PlainText, ()> {
        Ok(PlainText(try!(imp::open(&self.0, &nonce, &key))))
    }
}

pub struct RefKey {}

impl RefKey {
    pub fn seal(href: &mut HashRef, pt: PlainText) -> CipherText {
        // TODO(jos): WIP: Plug in encryption/crypto here.
        // Update cref with key.
        let key = imp::gen_key();
        href.persistent_ref.key = Some(wrap_key(key.clone()));

        let nonce = desc::Nonce::from_slice(&href.hash.bytes[..desc::NONCEBYTES]).unwrap();
        let ct = pt.to_ciphertext(&nonce, &key);
        href.persistent_ref.length = ct.len();

        ct
    }

    pub fn unseal(hash: &Hash, cref: &ChunkRef, ct: CipherTextRef) -> Result<PlainText, ()> {
        assert!(ct.len() >= cref.offset + cref.length);
        let ct = ct.slice(cref.offset, cref.offset + cref.length);
        match cref.key {
            Some(Key::XSalsa20Poly1305(ref key)) => {
                let nonce = desc::Nonce::from_slice(&hash.bytes[..desc::NONCEBYTES]).unwrap();
                Ok(try!(ct.to_plaintext(&nonce, &key)))
            }
            _ => panic!("Unknown blob key type"),
        }
    }
}

pub struct FixedKey {
    key: desc::Key,
}

impl FixedKey {
    pub fn new(key: desc::Key) -> FixedKey {
        FixedKey { key: key }
    }

    pub fn tie_knot(&self, pt: PlainText) -> CipherText {
        let nonce = imp::gen_nonce();
        let mut ct = pt.to_ciphertext(&nonce, &self.key);

        // Build footer from nonce and serialized ciphertext length.
        let ct_len = ct.len();
        let mut foot_pt = PlainText(nonce.as_ref().to_owned());
        foot_pt.0.write_u64::<LittleEndian>(ct_len as u64).unwrap();
        assert_eq!(foot_pt.len(), desc::footer_plain_bytes());

        // Tie the knot by sealing the nonce and ciphertext length.
        assert!(ct_len > desc::NONCEBYTES);
        let nonce = desc::Nonce::from_slice(&ct.0[ct_len - desc::NONCEBYTES..]).unwrap();
        ct.append(&mut foot_pt.to_ciphertext(&nonce, &self.key));

        // Return complete ciphertext.
        ct
    }

    fn untie_knot<'a>(&self, ct: CipherTextRef<'a>) -> Result<(CipherTextRef<'a>, PlainText), ()> {
        // Partial untie of knot: recover footer with nonce and ciphertext length.
        let foot_size = desc::footer_cipher_bytes();
        let (rest, foot_ct) = ct.split_from_right(foot_size);
        let nonce = desc::Nonce::from_slice(&rest.as_bytes()[rest.len() - desc::NONCEBYTES..])
            .unwrap();
        let foot_pt = try!(foot_ct.to_plaintext(&nonce, &self.key));

        let nonce = desc::Nonce::from_slice(&foot_pt.as_bytes()[..desc::NONCEBYTES]).unwrap();
        let ct_len = (&foot_pt.as_bytes()[desc::NONCEBYTES..]).read_u64::<LittleEndian>().unwrap();

        // Complete untie: recover plaintext.
        let (rest, ct) = rest.split_from_right(ct_len as usize);
        Ok((rest, try!(ct.to_plaintext(&nonce, &self.key))))
    }

    pub fn seal(&self, pt: PlainText) -> CipherText {
        // Seal with fixed key.
        self.tie_knot(pt)
    }

    pub fn unseal<'a, 'b>(&'a self,
                          ct: CipherTextRef<'b>)
                          -> Result<(CipherTextRef<'b>, PlainText), ()> {
        // Unseal with fixed key.
        self.untie_knot(ct)
    }
}
<|endoftext|>


<commit_before>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::parser;
    use robin_core::ast::Expression;

    #[test]
    fn booleans_should_return_a_boolean_node() {
        assert_eq!(parser::parse("true"), Expression::Boolean(true))
    }

    #[test]
    fn identifiers_that_look_like_booleans_should_return_identifiers() {
        assert_eq!(parser::parse("truedog"), Expression::Identifier("truedog".to_string()))
    }

    #[test]
    fn identifiers_should_return_a_identifier_node() {
        assert_eq!(parser::parse("hello"), Expression::Identifier("hello".to_string()))
    }

    #[test]
    fn decimals_should_return_a_number_node() {
        assert_eq!(parser::parse("47"), Expression::Number(47.0))
    }

    #[test]
    fn exponents_should_return_a_number_node() {
        assert_eq!(parser::parse("5e1"), Expression::Number(50.0))
    }

    #[test]
    fn binary_should_return_a_number_node() {
        assert_eq!(parser::parse("0b1"), Expression::Number(1.0))
    }

    #[test]
    fn octal_should_return_a_number_node() {
        assert_eq!(parser::parse("0o2"), Expression::Number(2.0))
    }

    #[test]
    fn hexadecimal_should_return_a_number_node() {
        assert_eq!(parser::parse("0xA"), Expression::Number(10.0))
    }
}
<commit_msg>Change tests to reflect parse changes<commit_after>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::parser;
    use robin_core::ast::Expression;

    #[test]
    fn booleans_should_return_a_boolean_node() {
        assert_eq!(parser::parse("true".to_string(),), Expression::Boolean(true))
    }

    #[test]
    fn identifiers_that_look_like_booleans_should_return_identifiers() {
        assert_eq!(parser::parse("truedog".to_string(),), Expression::Identifier("truedog".to_string()))
    }

    #[test]
    fn identifiers_should_return_a_identifier_node() {
        assert_eq!(parser::parse("hello".to_string(),), Expression::Identifier("hello".to_string()))
    }

    #[test]
    fn decimals_should_return_a_number_node() {
        assert_eq!(parser::parse("47".to_string(),), Expression::Number(47.0))
    }

    #[test]
    fn exponents_should_return_a_number_node() {
        assert_eq!(parser::parse("5e1".to_string(),), Expression::Number(50.0))
    }

    #[test]
    fn binary_should_return_a_number_node() {
        assert_eq!(parser::parse("0b1".to_string(),), Expression::Number(1.0))
    }

    #[test]
    fn octal_should_return_a_number_node() {
        assert_eq!(parser::parse("0o2".to_string(),), Expression::Number(2.0))
    }

    #[test]
    fn hexadecimal_should_return_a_number_node() {
        assert_eq!(parser::parse("0xA".to_string(),), Expression::Number(10.0))
    }
}
<|endoftext|>


<commit_before>//! Kata OS global memory management support

extern crate alloc;
use core::ops::Range;
use kata_memory_interface::MemoryError;
use kata_memory_interface::MemoryManagerInterface;
use kata_memory_interface::MemoryManagerStats;
use kata_memory_interface::ObjDesc;
use kata_memory_interface::ObjDescBundle;
use kata_os_common::camkes::{seL4_CPath, Camkes};
use kata_os_common::sel4_sys;
use log::{debug, error, info, trace, warn};
use smallvec::SmallVec;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Revoke;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Error;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_UntypedDesc;
use sel4_sys::seL4_Untyped_Describe;
use sel4_sys::seL4_Untyped_Retype;
use sel4_sys::seL4_Word;

fn delete_path(path: &seL4_CPath) -> seL4_Result {
    unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }
}
fn revoke_cap(cptr: seL4_CPtr) -> seL4_Result {
    let path = Camkes::top_level_path(cptr);
    unsafe { seL4_CNode_Revoke(path.0, path.1, path.2 as u8) }
}
fn untyped_describe(cptr: seL4_CPtr) -> seL4_Untyped_Describe {
    unsafe { seL4_Untyped_Describe(cptr) }
}

// SmallVec capacity for untyped memory slabs. There are two instances;
// one for anonymous memory and one for device-backed memory. The memory
// manager is expected to be setup as a static global so these data
// structures will land in .bss and only overflow to the heap if
// initialized with more than this count.
const UNTYPED_SLAB_CAPACITY: usize = 64; // # slabs kept inline

// The MemoryManager supports allocating & freeing seL4 objects that are
// instantiated from UntypedMemory "slabs". Allocation causes untyped memory
// to be converted to concrete types. Freeing deletes the specified capabilities
// and updates the bookkeeping. Note that a free only releases the specified
// cap; if there are dups or derived objects the memory will not be returned
// to the untyped slab from which it was allocated and the bookkeeping done
// here will be out of sync with the kernel.
// TODO(sleffler): support device-backed memory objects
#[derive(Debug)]
struct UntypedSlab {
    pub size_bits: usize,       // NB: only used to sort
    pub _base_paddr: seL4_Word, // Physical address of slab start
    pub _last_paddr: seL4_Word, // Physical address of slab end
    pub cptr: seL4_CPtr,        // seL4 untyped object
    pub _next_paddr: seL4_Word, // Physical address of next available chunk
}
impl UntypedSlab {
    fn new(ut: &seL4_UntypedDesc, cptr: seL4_CPtr) -> Self {
        UntypedSlab {
            size_bits: ut.size_bits(),
            _base_paddr: ut.paddr,
            _last_paddr: ut.paddr + (1 << ut.size_bits()),
            cptr,
            _next_paddr: ut.paddr,
        }
    }
    fn _size(&self) -> usize { l2tob(self.size_bits) }
    fn size_bits(&self) -> usize { self.size_bits }
}
pub struct MemoryManager {
    untypeds: SmallVec<[UntypedSlab; UNTYPED_SLAB_CAPACITY]>,
    _device_untypeds: SmallVec<[UntypedSlab; UNTYPED_SLAB_CAPACITY]>,
    cur_untyped: usize,
    _cur_device_untyped: usize,

    total_bytes: usize,     // Total available space
    allocated_bytes: usize, // Amount of space currently allocated
    requested_bytes: usize, // Amount of space allocated over all time
    overhead_bytes: usize,

    allocated_objs: usize, // # seL4 objects currently allocated
    requested_objs: usize, // # seL4 objects allocated over all time

    // Retype requests failed due to insufficient available memory.
    untyped_slab_too_small: usize,

    // Alloc requests failed due to lack of untyped memory (NB: may be
    // due to fragmentation of untyped slabs).
    out_of_memory: usize,
}

fn _howmany(value: usize, unit: usize) -> usize { value + (unit - 1) / unit }
fn _round_up(value: usize, align: usize) -> usize { _howmany(value, align) * align }

// Log2 bits to bytes.
fn l2tob(size_bits: usize) -> usize { 1 << size_bits }

impl MemoryManager {
    // Creates a new MemoryManager instance. The allocator is seeded
    // from the untyped memory descriptors.
    pub fn new(slots: Range<seL4_CPtr>, untypeds: &[seL4_UntypedDesc]) -> Self {
        assert!(!untypeds.is_empty());
        assert_eq!(slots.end - slots.start, untypeds.len());
        let mut m = MemoryManager {
            untypeds: SmallVec::new(),
            _device_untypeds: SmallVec::new(),
            cur_untyped: 0,
            _cur_device_untyped: 0,

            total_bytes: 0,
            allocated_bytes: 0,
            requested_bytes: 0,
            overhead_bytes: 0,

            allocated_objs: 0,
            requested_objs: 0,

            untyped_slab_too_small: 0,
            out_of_memory: 0,
        };
        for (ut_index, ut) in untypeds.iter().enumerate() {
            #[cfg(feature = "CONFIG_NOISY_UNTYPEDS")]
            log::info!("slot {} {:?}", slots.start + ut_index, ut);
            if ut.is_device() {
                m._device_untypeds
                    .push(UntypedSlab::new(ut, slots.start + ut_index));
            } else {
                if ut.is_tainted() {
                    revoke_cap(slots.start + ut_index).expect("revoke untyped");
                }
                m.untypeds
                    .push(UntypedSlab::new(ut, slots.start + ut_index));
                // NB: must get current state of ut as it will reflect resources
                //   allocated before we run.
                let info = untyped_describe(slots.start + ut_index);
                assert_eq!(info.sizeBits, ut.size_bits());
                let size = l2tob(info.sizeBits);
                // We only have the remainder available for allocations.
                m.total_bytes += info.remainingBytes;
                // Use overhead to track memory allocated out of our control.
                m.overhead_bytes += size - info.remainingBytes;
            }
        }
        // Sort non-device slabs by descending size.
        // TODO(sleffler): assumes slabs are empty, maybe sort by available space
        m.untypeds
            .sort_unstable_by(|a, b| b.size_bits().cmp(&a.size_bits()));
        m
    }

    // Total available space.
    pub fn total_available_space(&self) -> usize { self.total_bytes }
    // Current allocated space
    pub fn allocated_space(&self) -> usize { self.allocated_bytes }
    // Current free space.
    pub fn free_space(&self) -> usize { self.total_bytes - self.allocated_bytes }
    // Total space allocated over time
    pub fn total_requested_space(&self) -> usize { self.requested_bytes }
    // Current allocated space out of our control.
    pub fn overhead_space(&self) -> usize { self.overhead_bytes }

    // Current allocated objects
    pub fn allocated_objs(&self) -> usize { self.allocated_objs }
    // Total objects allocated over time
    pub fn total_requested_objs(&self) -> usize { self.requested_objs }

    pub fn untyped_slab_too_small(&self) -> usize { self.untyped_slab_too_small }
    pub fn out_of_memory(&self) -> usize { self.out_of_memory }

    fn retype_untyped(free_untyped: seL4_CPtr, root: seL4_CPtr, obj: &ObjDesc) -> seL4_Result {
        unsafe {
            seL4_Untyped_Retype(
                free_untyped,
                /*type=*/ obj.type_.into(),
                /*size_bits=*/ obj.retype_size_bits().unwrap(),
                /*root=*/ root,
                /*node_index=*/ 0, // Ignored 'cuz depth is zero
                /*node_depth=*/ 0, // NB: store in cnode
                /*node_offset=*/ obj.cptr,
                /*num_objects=*/ obj.retype_count(),
            )
        }
    }

    fn delete_caps(root: seL4_CPtr, depth: u8, od: &ObjDesc) -> seL4_Result {
        for offset in 0..od.retype_count() {
            let path = (root, od.cptr + offset, depth as usize);
            if let Err(e) = delete_path(&path) {
                warn!("DELETE {:?} failed: od {:?} error {:?}", &path, od, e);
            }
        }
        Ok(())
    }
}

impl MemoryManagerInterface for MemoryManager {
    fn alloc(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError> {
        trace!("alloc {:?}", bundle);

        // TODO(sleffler): split by device vs no-device (or allow mixing)
        let first_ut = self.cur_untyped;
        let mut ut_index = first_ut;

        let mut allocated_bytes: usize = 0;
        let mut allocated_objs: usize = 0;

        for od in &bundle.objs {
            // NB: we don't check slots are available (the kernel will tell us).
            // TODO(sleffler): maybe check size_bytes() against untyped slab?
            //    (we depend on the kernel for now)
            while let Err(e) =
                // NB: we don't allocate ASIDPool objects but if we did it
                //   would fail because it needs to map to an UntypedObject
                MemoryManager::retype_untyped(
                    self.untypeds[ut_index].cptr,
                    bundle.cnode,
                    od,
                )
            {
                if e != seL4_Error::seL4_NotEnoughMemory {
                    // Should not happen.
                    // TODO(sleffler): reclaim allocations
                    error!("Allocation request failed (retype returned {:?})", e);
                    return Err(MemoryError::UnknownMemoryError);
                }
                // This untyped does not have enough available space, try
                // the next slab until we exhaust all slabs. This is the best
                // we can do without per-slab bookkeeping.
                self.untyped_slab_too_small += 1;
                ut_index = (ut_index + 1) % self.untypeds.len();
                debug!("Advance to untyped slab {}", ut_index);
                if ut_index == first_ut {
                    // TODO(sleffler): reclaim allocations
                    self.out_of_memory += 1;
                    debug!("Allocation request failed (out of space)");
                    return Err(MemoryError::AllocFailed);
                }
            }
            allocated_objs += od.retype_count();
            allocated_bytes += od.size_bytes().unwrap();
        }
        self.cur_untyped = ut_index;

        self.allocated_bytes += allocated_bytes;
        self.allocated_objs += allocated_objs;

        // NB: does not include requests that fail
        self.requested_objs += allocated_objs;
        self.requested_bytes += allocated_bytes;

        Ok(())
    }
    fn free(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError> {
        trace!("free {:?}", bundle);

        for od in &bundle.objs {
            // TODO(sleffler): support leaving objects so client can do bulk
            //   reclaim on exit (maybe require cptr != 0)
            if MemoryManager::delete_caps(bundle.cnode, bundle.depth, od).is_ok() {
                // NB: atm we do not do per-untyped bookkeeping so just track
                //   global stats.
                // TODO(sleffler): temp workaround for bad bookkeeping / client mis-handling
                let size_bytes = od.size_bytes().ok_or(MemoryError::ObjTypeInvalid)?;
                if size_bytes <= self.allocated_bytes {
                    self.allocated_bytes -= size_bytes;
                    self.allocated_objs -= od.retype_count();
                } else {
                    debug!("Underflow on free of {:?}", od);
                }
            }
        }
        Ok(())
    }
    fn stats(&self) -> Result<MemoryManagerStats, MemoryError> {
        Ok(MemoryManagerStats {
            allocated_bytes: self.allocated_space(),
            free_bytes: self.free_space(),
            total_requested_bytes: self.total_requested_space(),
            overhead_bytes: self.overhead_space(),

            allocated_objs: self.allocated_objs(),
            total_requested_objs: self.total_requested_objs(),

            untyped_slab_too_small: self.untyped_slab_too_small(),
            out_of_memory: self.out_of_memory(),
        })
    }
    fn debug(&self) -> Result<(), MemoryError> {
        // TODO(sleffler): only shows !device slabs
        for ut in &self.untypeds {
            let info = untyped_describe(ut.cptr);
            let size = l2tob(info.sizeBits);
            info!(
                "[{}] allocated {} free {}",
                ut.cptr,
                size - info.remainingBytes,
                info.remainingBytes,
            );
        }
        Ok(())
    }
}
<commit_msg>MemoryManager: sort untyped slabs by available space<commit_after>//! Kata OS global memory management support

extern crate alloc;
use core::ops::Range;
use kata_memory_interface::MemoryError;
use kata_memory_interface::MemoryManagerInterface;
use kata_memory_interface::MemoryManagerStats;
use kata_memory_interface::ObjDesc;
use kata_memory_interface::ObjDescBundle;
use kata_os_common::camkes::{seL4_CPath, Camkes};
use kata_os_common::sel4_sys;
use log::{debug, error, info, trace, warn};
use smallvec::SmallVec;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Revoke;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Error;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_UntypedDesc;
use sel4_sys::seL4_Untyped_Describe;
use sel4_sys::seL4_Untyped_Retype;
use sel4_sys::seL4_Word;

fn delete_path(path: &seL4_CPath) -> seL4_Result {
    unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }
}
fn revoke_cap(cptr: seL4_CPtr) -> seL4_Result {
    let path = Camkes::top_level_path(cptr);
    unsafe { seL4_CNode_Revoke(path.0, path.1, path.2 as u8) }
}
fn untyped_describe(cptr: seL4_CPtr) -> seL4_Untyped_Describe {
    unsafe { seL4_Untyped_Describe(cptr) }
}

// SmallVec capacity for untyped memory slabs. There are two instances;
// one for anonymous memory and one for device-backed memory. The memory
// manager is expected to be setup as a static global so these data
// structures will land in .bss and only overflow to the heap if
// initialized with more than this count.
const UNTYPED_SLAB_CAPACITY: usize = 64; // # slabs kept inline

// The MemoryManager supports allocating & freeing seL4 objects that are
// instantiated from UntypedMemory "slabs". Allocation causes untyped memory
// to be converted to concrete types. Freeing deletes the specified capabilities
// and updates the bookkeeping. Note that a free only releases the specified
// cap; if there are dups or derived objects the memory will not be returned
// to the untyped slab from which it was allocated and the bookkeeping done
// here will be out of sync with the kernel.
// TODO(sleffler): support device-backed memory objects
#[derive(Debug)]
struct UntypedSlab {
    pub size_bits: usize,       // NB: only used to sort
    pub free_bytes: usize,      // Available space in slab
    pub _base_paddr: seL4_Word, // Physical address of slab start
    pub _last_paddr: seL4_Word, // Physical address of slab end
    pub cptr: seL4_CPtr,        // seL4 untyped object
}
impl UntypedSlab {
    fn new(ut: &seL4_UntypedDesc, free_bytes: usize, cptr: seL4_CPtr) -> Self {
        UntypedSlab {
            size_bits: ut.size_bits(),
            free_bytes,
            _base_paddr: ut.paddr,
            _last_paddr: ut.paddr + (1 << ut.size_bits()),
            cptr,
        }
    }
    fn _size(&self) -> usize { l2tob(self.size_bits) }
    fn size_bits(&self) -> usize { self.size_bits }
}
pub struct MemoryManager {
    untypeds: SmallVec<[UntypedSlab; UNTYPED_SLAB_CAPACITY]>,
    _device_untypeds: SmallVec<[UntypedSlab; UNTYPED_SLAB_CAPACITY]>,
    cur_untyped: usize,
    _cur_device_untyped: usize,

    total_bytes: usize,     // Total available space
    allocated_bytes: usize, // Amount of space currently allocated
    requested_bytes: usize, // Amount of space allocated over all time
    overhead_bytes: usize,

    allocated_objs: usize, // # seL4 objects currently allocated
    requested_objs: usize, // # seL4 objects allocated over all time

    // Retype requests failed due to insufficient available memory.
    untyped_slab_too_small: usize,

    // Alloc requests failed due to lack of untyped memory (NB: may be
    // due to fragmentation of untyped slabs).
    out_of_memory: usize,
}

fn _howmany(value: usize, unit: usize) -> usize { value + (unit - 1) / unit }
fn _round_up(value: usize, align: usize) -> usize { _howmany(value, align) * align }

// Log2 bits to bytes.
fn l2tob(size_bits: usize) -> usize { 1 << size_bits }

impl MemoryManager {
    // Creates a new MemoryManager instance. The allocator is seeded
    // from the untyped memory descriptors.
    pub fn new(slots: Range<seL4_CPtr>, untypeds: &[seL4_UntypedDesc]) -> Self {
        assert!(!untypeds.is_empty());
        assert_eq!(slots.end - slots.start, untypeds.len());
        let mut m = MemoryManager {
            untypeds: SmallVec::new(),
            _device_untypeds: SmallVec::new(),
            cur_untyped: 0,
            _cur_device_untyped: 0,

            total_bytes: 0,
            allocated_bytes: 0,
            requested_bytes: 0,
            overhead_bytes: 0,

            allocated_objs: 0,
            requested_objs: 0,

            untyped_slab_too_small: 0,
            out_of_memory: 0,
        };
        for (ut_index, ut) in untypeds.iter().enumerate() {
            #[cfg(feature = "CONFIG_NOISY_UNTYPEDS")]
            log::info!("slot {} {:?}", slots.start + ut_index, ut);
            let slab_size = l2tob(ut.size_bits());
            if ut.is_device() {
                m._device_untypeds
                    .push(UntypedSlab::new(ut, slab_size, slots.start + ut_index));
            } else {
                if ut.is_tainted() {
                    revoke_cap(slots.start + ut_index).expect("revoke untyped");
                }
                // NB: must get current state of ut as it will reflect resources
                //   allocated before we run.
                let info = untyped_describe(slots.start + ut_index);
                assert_eq!(info.sizeBits, ut.size_bits());

                // We only have the remainder available for allocations.
                m.untypeds
                    .push(UntypedSlab::new(ut, info.remainingBytes, slots.start + ut_index));
                m.total_bytes += info.remainingBytes;

                // Use overhead to track memory allocated out of our control.
                m.overhead_bytes += slab_size - info.remainingBytes;
            }
        }
        // Sort non-device slabs by descending amount of free space.
        m.untypeds
            .sort_unstable_by(|a, b| b.free_bytes.cmp(&a.free_bytes));
        m
    }

    // Total available space.
    pub fn total_available_space(&self) -> usize { self.total_bytes }
    // Current allocated space
    pub fn allocated_space(&self) -> usize { self.allocated_bytes }
    // Current free space.
    pub fn free_space(&self) -> usize { self.total_bytes - self.allocated_bytes }
    // Total space allocated over time
    pub fn total_requested_space(&self) -> usize { self.requested_bytes }
    // Current allocated space out of our control.
    pub fn overhead_space(&self) -> usize { self.overhead_bytes }

    // Current allocated objects
    pub fn allocated_objs(&self) -> usize { self.allocated_objs }
    // Total objects allocated over time
    pub fn total_requested_objs(&self) -> usize { self.requested_objs }

    pub fn untyped_slab_too_small(&self) -> usize { self.untyped_slab_too_small }
    pub fn out_of_memory(&self) -> usize { self.out_of_memory }

    fn retype_untyped(free_untyped: seL4_CPtr, root: seL4_CPtr, obj: &ObjDesc) -> seL4_Result {
        unsafe {
            seL4_Untyped_Retype(
                free_untyped,
                /*type=*/ obj.type_.into(),
                /*size_bits=*/ obj.retype_size_bits().unwrap(),
                /*root=*/ root,
                /*node_index=*/ 0, // Ignored 'cuz depth is zero
                /*node_depth=*/ 0, // NB: store in cnode
                /*node_offset=*/ obj.cptr,
                /*num_objects=*/ obj.retype_count(),
            )
        }
    }

    fn delete_caps(root: seL4_CPtr, depth: u8, od: &ObjDesc) -> seL4_Result {
        for offset in 0..od.retype_count() {
            let path = (root, od.cptr + offset, depth as usize);
            if let Err(e) = delete_path(&path) {
                warn!("DELETE {:?} failed: od {:?} error {:?}", &path, od, e);
            }
        }
        Ok(())
    }
}

impl MemoryManagerInterface for MemoryManager {
    fn alloc(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError> {
        trace!("alloc {:?}", bundle);

        // TODO(sleffler): split by device vs no-device (or allow mixing)
        let first_ut = self.cur_untyped;
        let mut ut_index = first_ut;

        let mut allocated_bytes: usize = 0;
        let mut allocated_objs: usize = 0;

        for od in &bundle.objs {
            // NB: we don't check slots are available (the kernel will tell us).
            // TODO(sleffler): maybe check size_bytes() against untyped slab?
            //    (we depend on the kernel for now)
            while let Err(e) =
                // NB: we don't allocate ASIDPool objects but if we did it
                //   would fail because it needs to map to an UntypedObject
                MemoryManager::retype_untyped(
                    self.untypeds[ut_index].cptr,
                    bundle.cnode,
                    od,
                )
            {
                if e != seL4_Error::seL4_NotEnoughMemory {
                    // Should not happen.
                    // TODO(sleffler): reclaim allocations
                    error!("Allocation request failed (retype returned {:?})", e);
                    return Err(MemoryError::UnknownMemoryError);
                }
                // This untyped does not have enough available space, try
                // the next slab until we exhaust all slabs. This is the best
                // we can do without per-slab bookkeeping.
                self.untyped_slab_too_small += 1;
                ut_index = (ut_index + 1) % self.untypeds.len();
                debug!("Advance to untyped slab {}", ut_index);
                if ut_index == first_ut {
                    // TODO(sleffler): reclaim allocations
                    self.out_of_memory += 1;
                    debug!("Allocation request failed (out of space)");
                    return Err(MemoryError::AllocFailed);
                }
            }
            allocated_objs += od.retype_count();
            allocated_bytes += od.size_bytes().unwrap();
        }
        self.cur_untyped = ut_index;

        self.allocated_bytes += allocated_bytes;
        self.allocated_objs += allocated_objs;

        // NB: does not include requests that fail
        self.requested_objs += allocated_objs;
        self.requested_bytes += allocated_bytes;

        Ok(())
    }
    fn free(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError> {
        trace!("free {:?}", bundle);

        for od in &bundle.objs {
            // TODO(sleffler): support leaving objects so client can do bulk
            //   reclaim on exit (maybe require cptr != 0)
            if MemoryManager::delete_caps(bundle.cnode, bundle.depth, od).is_ok() {
                // NB: atm we do not do per-untyped bookkeeping so just track
                //   global stats.
                // TODO(sleffler): temp workaround for bad bookkeeping / client mis-handling
                let size_bytes = od.size_bytes().ok_or(MemoryError::ObjTypeInvalid)?;
                if size_bytes <= self.allocated_bytes {
                    self.allocated_bytes -= size_bytes;
                    self.allocated_objs -= od.retype_count();
                } else {
                    debug!("Underflow on free of {:?}", od);
                }
            }
        }
        Ok(())
    }
    fn stats(&self) -> Result<MemoryManagerStats, MemoryError> {
        Ok(MemoryManagerStats {
            allocated_bytes: self.allocated_space(),
            free_bytes: self.free_space(),
            total_requested_bytes: self.total_requested_space(),
            overhead_bytes: self.overhead_space(),

            allocated_objs: self.allocated_objs(),
            total_requested_objs: self.total_requested_objs(),

            untyped_slab_too_small: self.untyped_slab_too_small(),
            out_of_memory: self.out_of_memory(),
        })
    }
    fn debug(&self) -> Result<(), MemoryError> {
        // TODO(sleffler): only shows !device slabs
        for ut in &self.untypeds {
            let info = untyped_describe(ut.cptr);
            let size = l2tob(info.sizeBits);
            info!(
                "[{}] allocated {} free {}",
                ut.cptr,
                size - info.remainingBytes,
                info.remainingBytes,
            );
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn solve_random() {
    let a: Array2<f64> = random((3, 3));
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[test]
fn solve_random_t() {
    let a: Array2<f64> = random((3, 3).f());
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[test]
fn solve_factorized() {
    let a: Array2<f64> = random((3, 3));
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[test]
fn solve_factorized_t() {
    let a: Array2<f64> = random((3, 3).f());
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[test]
fn rcond() {
    macro_rules! rcond {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a: Array2<$elem> = random_hpd($rows);
            let rcond = 1. / (a.opnorm_one().unwrap() * a.inv().unwrap().opnorm_one().unwrap());
            assert_aclose!(a.rcond().unwrap(), rcond, $atol);
            assert_aclose!(a.rcond_into().unwrap(), rcond, $atol);
        };
    }
    for rows in 1..6 {
        rcond!(f64, rows, 0.2);
        rcond!(f32, rows, 0.5);
        rcond!(c64, rows, 0.2);
        rcond!(c32, rows, 0.5);
    }
}

#[test]
fn rcond_hilbert() {
    macro_rules! rcond_hilbert {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::from_shape_fn(($rows, $rows), |(i, j)| {
                1. / (i as $elem + j as $elem - 1.)
            });
            assert_aclose!(a.rcond().unwrap(), 0., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 0., $atol);
        };
    }
    rcond_hilbert!(f64, 10, 1e-9);
    rcond_hilbert!(f32, 10, 1e-3);
}

#[test]
fn rcond_identity() {
    macro_rules! rcond_identity {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::eye($rows);
            assert_aclose!(a.rcond().unwrap(), 1., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 1., $atol);
        };
    }
    for rows in 1..6 {
        rcond_identity!(f64, rows, 1e-9);
        rcond_identity!(f32, rows, 1e-3);
        rcond_identity!(c64, rows, 1e-9);
        rcond_identity!(c32, rows, 1e-3);
    }
}
<commit_msg>Add tests for matching shape checks in Solve<commit_after>use ndarray::*;
use ndarray_linalg::*;

#[should_panic]
#[test]
fn solve_shape_mismatch() {
    let a: Array2<f64> = random((3, 3));
    let b: Array1<f64> = random(2);
    let _ = a.solve_into(b);
}

#[test]
fn solve_random() {
    let a: Array2<f64> = random((3, 3));
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[should_panic]
#[test]
fn solve_t_shape_mismatch() {
    let a: Array2<f64> = random((3, 3).f());
    let b: Array1<f64> = random(4);
    let _ = a.solve_into(b);
}

#[test]
fn solve_random_t() {
    let a: Array2<f64> = random((3, 3).f());
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[should_panic]
#[test]
fn solve_factorized_shape_mismatch() {
    let a: Array2<f64> = random((3, 3));
    let b: Array1<f64> = random(4);
    let f = a.factorize_into().unwrap();
    let _ = f.solve_into(b);
}

#[test]
fn solve_factorized() {
    let a: Array2<f64> = random((3, 3));
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[should_panic]
#[test]
fn solve_factorized_t_shape_mismatch() {
    let a: Array2<f64> = random((3, 3).f());
    let b: Array1<f64> = random(4);
    let f = a.factorize_into().unwrap();
    let _ = f.solve_into(b);
}

#[test]
fn solve_factorized_t() {
    let a: Array2<f64> = random((3, 3).f());
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[test]
fn rcond() {
    macro_rules! rcond {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a: Array2<$elem> = random_hpd($rows);
            let rcond = 1. / (a.opnorm_one().unwrap() * a.inv().unwrap().opnorm_one().unwrap());
            assert_aclose!(a.rcond().unwrap(), rcond, $atol);
            assert_aclose!(a.rcond_into().unwrap(), rcond, $atol);
        };
    }
    for rows in 1..6 {
        rcond!(f64, rows, 0.2);
        rcond!(f32, rows, 0.5);
        rcond!(c64, rows, 0.2);
        rcond!(c32, rows, 0.5);
    }
}

#[test]
fn rcond_hilbert() {
    macro_rules! rcond_hilbert {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::from_shape_fn(($rows, $rows), |(i, j)| {
                1. / (i as $elem + j as $elem - 1.)
            });
            assert_aclose!(a.rcond().unwrap(), 0., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 0., $atol);
        };
    }
    rcond_hilbert!(f64, 10, 1e-9);
    rcond_hilbert!(f32, 10, 1e-3);
}

#[test]
fn rcond_identity() {
    macro_rules! rcond_identity {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::eye($rows);
            assert_aclose!(a.rcond().unwrap(), 1., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 1., $atol);
        };
    }
    for rows in 1..6 {
        rcond_identity!(f64, rows, 1e-9);
        rcond_identity!(f32, rows, 1e-3);
        rcond_identity!(c64, rows, 1e-9);
        rcond_identity!(c32, rows, 1e-3);
    }
}
<|endoftext|>


<commit_before>use x86::__m128i;
use v128::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Alternatively add and subtract packed single-precision (32-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsub))]
pub unsafe fn _mm_addsub_ps(a: f32x4, b: f32x4) -> f32x4 {
    addsubps(a, b)
}

/// Alternatively add and subtract packed double-precision (64-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsub))]
pub unsafe fn _mm_addsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    addsubpd(a, b)
}

/// Horizontally add adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hadd))]
pub unsafe fn _mm_hadd_pd(a: f64x2, b: f64x2) -> f64x2 {
    haddpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hadd))]
pub unsafe fn _mm_hadd_ps(a: f32x4, b: f32x4) -> f32x4 {
    haddps(a, b)
}

/// Horizontally subtract adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsub))]
pub unsafe fn _mm_hsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    hsubpd(a, b)
}

/// Load 128-bits of integer data from unaligned memory.
/// This intrinsic may perform better than `_mm_loadu_si128`
/// when the data crosses a cache line boundary.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(lddqu))]
pub unsafe fn _mm_lddqu_si128(mem_addr: *const __m128i) -> __m128i {
    lddqu(mem_addr as *const _)
}

#[allow(improper_ctypes)]
extern {
    #[link_name = "llvm.x86.sse3.addsub.ps"]
    fn addsubps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.addsub.pd"]
    fn addsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.pd"]
    fn haddpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.ps"]
    fn haddps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.hsub.pd"]
    fn hsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.ldu.dq"]
    fn lddqu(mem_addr: *const i8) -> __m128i;
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use v128::*;
    use x86::sse3 as sse3;

    #[simd_test = "sse3"]
    unsafe fn _mm_addsub_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_addsub_ps(a, b);
        assert_eq!(r, f32x4::new(99.0, 25.0, 0.0, -15.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_addsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_addsub_pd(a, b);
        assert_eq!(r, f64x2::new(99.0, 25.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hadd_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hadd_pd(a, b);
        assert_eq!(r, f64x2::new(4.0, -80.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hadd_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_hadd_ps(a, b);
        assert_eq!(r, f32x4::new(4.0, -10.0, -80.0, -5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hsub_pd(a, b);
        assert_eq!(r, f64x2::new(-6.0, -120.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_lddqu_si128() {
        let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        let r = sse3::_mm_lddqu_si128(&a);
        assert_eq!(a, r);
    }
}<commit_msg>sse3: _mm_hsub_ps<commit_after>use x86::__m128i;
use v128::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Alternatively add and subtract packed single-precision (32-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubps))]
pub unsafe fn _mm_addsub_ps(a: f32x4, b: f32x4) -> f32x4 {
    addsubps(a, b)
}

/// Alternatively add and subtract packed double-precision (64-bit)
/// floating-point elements in `a` to/from packed elements in `b`.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(addsubpd))]
pub unsafe fn _mm_addsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    addsubpd(a, b)
}

/// Horizontally add adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddpd))]
pub unsafe fn _mm_hadd_pd(a: f64x2, b: f64x2) -> f64x2 {
    haddpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(haddps))]
pub unsafe fn _mm_hadd_ps(a: f32x4, b: f32x4) -> f32x4 {
    haddps(a, b)
}

/// Horizontally subtract adjacent pairs of double-precision (64-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubpd))]
pub unsafe fn _mm_hsub_pd(a: f64x2, b: f64x2) -> f64x2 {
    hsubpd(a, b)
}

/// Horizontally add adjacent pairs of single-precision (32-bit)
/// floating-point elements in `a` and `b`, and pack the results.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(hsubps))]
pub unsafe fn _mm_hsub_ps(a: f32x4, b: f32x4) -> f32x4 {
    hsubps(a, b)
}

/// Load 128-bits of integer data from unaligned memory.
/// This intrinsic may perform better than `_mm_loadu_si128`
/// when the data crosses a cache line boundary.
#[inline(always)]
#[target_feature = "+sse3"]
#[cfg_attr(test, assert_instr(lddqu))]
pub unsafe fn _mm_lddqu_si128(mem_addr: *const __m128i) -> __m128i {
    lddqu(mem_addr as *const _)
}

#[allow(improper_ctypes)]
extern {
    #[link_name = "llvm.x86.sse3.addsub.ps"]
    fn addsubps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.addsub.pd"]
    fn addsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.pd"]
    fn haddpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hadd.ps"]
    fn haddps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.hsub.pd"]
    fn hsubpd(a: f64x2, b: f64x2) -> f64x2;
    #[link_name = "llvm.x86.sse3.hsub.ps"]
    fn hsubps(a: f32x4, b: f32x4) -> f32x4;
    #[link_name = "llvm.x86.sse3.ldu.dq"]
    fn lddqu(mem_addr: *const i8) -> __m128i;
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use v128::*;
    use x86::sse3 as sse3;

    #[simd_test = "sse3"]
    unsafe fn _mm_addsub_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_addsub_ps(a, b);
        assert_eq!(r, f32x4::new(99.0, 25.0, 0.0, -15.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_addsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_addsub_pd(a, b);
        assert_eq!(r, f64x2::new(99.0, 25.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hadd_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hadd_pd(a, b);
        assert_eq!(r, f64x2::new(4.0, -80.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hadd_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_hadd_ps(a, b);
        assert_eq!(r, f32x4::new(4.0, -10.0, -80.0, -5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hsub_pd() {
        let a = f64x2::new(-1.0, 5.0);
        let b = f64x2::new(-100.0, 20.0);
        let r = sse3::_mm_hsub_pd(a, b);
        assert_eq!(r, f64x2::new(-6.0, -120.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_hsub_ps() {
        let a = f32x4::new(-1.0, 5.0, 0.0, -10.0);
        let b = f32x4::new(-100.0, 20.0, 0.0, -5.0);
        let r = sse3::_mm_hsub_ps(a, b);
        assert_eq!(r, f32x4::new(-6.0, 10.0, -120.0, 5.0));
    }

    #[simd_test = "sse3"]
    unsafe fn _mm_lddqu_si128() {
        let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        let r = sse3::_mm_lddqu_si128(&a);
        assert_eq!(a, r);
    }
}<|endoftext|>