<commit_before>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = xyz_to_rec709_matrix();

  let mut opos = 0;
  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = inb[pos];
    let a = inb[pos+1];
    let b = inb[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    out[opos+0] = r;
    out[opos+1] = g;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  // Normalize xyz_to_cam so that xyz_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += xyz_to_cam[i][j];
    }
    for j in 0..3 {
      xyz_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        xyz_to_cam[i][j] / num
      };
    }
  }

  pseudoinverse(xyz_to_cam)
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let mut rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Normalize rgb_to_xyz so that rgb_to_xyz * (1,1,1) is (1,1,1)
  for i in 0..3 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_xyz[i][j];
    }
    for j in 0..3 {
      rgb_to_xyz[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_xyz[i][j] / num
      };
    }
  }

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D65 White
  let xw = 95.074; let yw = 100.0; let zw = 108.883;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l,a,b)
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    val.powf(1.0 / 3.0)
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D65 White
  let xw = 95.074; let yw = 100.0; let zw = 108.883;

  let x = xw * labinvf((1.0/116.0) * (l+16.0) + (1.0/500.0) * a);
  let y = yw * labinvf((1.0/116.0) * (l+16.0));
  let z = zw * labinvf((1.0/116.0) * (l+16.0) - (1.0/200.0) * b);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val.powf(3.0)
  } else {
    val * multiplier + constant
  }
}
<commit_msg>colorspaces: Improve the Lab transform<commit_after>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = xyz_to_rec709_matrix();

  let mut opos = 0;
  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = inb[pos];
    let a = inb[pos+1];
    let b = inb[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    out[opos+0] = r;
    out[opos+1] = g;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  // Normalize xyz_to_cam so that xyz_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += xyz_to_cam[i][j];
    }
    for j in 0..3 {
      xyz_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        xyz_to_cam[i][j] / num
      };
    }
  }

  pseudoinverse(xyz_to_cam)
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let mut rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Normalize rgb_to_xyz so that rgb_to_xyz * (1,1,1) is (1,1,1)
  for i in 0..3 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_xyz[i][j];
    }
    for j in 0..3 {
      rgb_to_xyz[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_xyz[i][j] / num
      };
    }
  }

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l/100.0,(a+128.0)/256.0,(b+128.0)/256.0)
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    val.powf(1.0 / 3.0)
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let cl = l * 100.0;
  let ca = (a * 256.0) - 128.0;
  let cb = (b * 256.0) - 128.0;

  let x = xw * labinvf((1.0/116.0) * (cl+16.0) + (1.0/500.0) * ca);
  let y = yw * labinvf((1.0/116.0) * (cl+16.0));
  let z = zw * labinvf((1.0/116.0) * (cl+16.0) - (1.0/200.0) * cb);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val.powf(3.0)
  } else {
    val * multiplier + constant
  }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate http_event_store as es;

mod support;

use support::*;

#[test]
fn it_interacts_with_event_store() {
    let client = es::client::Client::new();
    let stream_name = test_stream_name();
    let created_event_id =  uuid::Uuid::new_v4();

    let mut events: Vec<Box<es::event::Event>> = vec![
        Box::new(TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: created_event_id.clone() }),
        Box::new(TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: uuid::Uuid::new_v4() })
    ];

    client.append_to_stream(&stream_name, 987, events);

    let stream = client.read_stream_events_forward(&stream_name, 0, 1, true).unwrap();

    assert_eq!("task-renamed", stream.entries[0].event_type);
    assert_eq!("task-created", stream.entries[1].event_type);
    assert_eq!(created_event_id.hyphenated().to_string(), stream.entries[1].event_id);
}

fn test_stream_name() -> String {
    format!("task-{}", time::get_time().sec)
}
<commit_msg>Re-factor a test<commit_after>extern crate serde;
extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate http_event_store as es;

mod support;

use support::*;

#[test]
fn it_interacts_with_event_store() {
    let created_id = "baca1a30-b6f1-470b-b68e-f79338020327";
    let renamed_id = "cbad187b-2fd0-4ad2-b78b-80d83f1ff303";
    let events: Vec<Box<es::event::Event>> = vec![
        Box::new(TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: uuid::Uuid::parse_str("baca1a30-b6f1-470b-b68e-f79338020327").unwrap() }),
        Box::new(TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: uuid::Uuid::parse_str("cbad187b-2fd0-4ad2-b78b-80d83f1ff303").unwrap() })
    ];

    let client = es::client::Client::new();
    let stream_name = test_stream_name();
    client.append_to_stream(&stream_name, 987, events);
    let stream = client.read_stream_events_forward(&stream_name, 0, 1, true).unwrap();

    assert_eq!("task-renamed", stream.entries[0].event_type);
    assert_eq!("task-created", stream.entries[1].event_type);
    assert_eq!("cbad187b-2fd0-4ad2-b78b-80d83f1ff303", stream.entries[0].event_id);
    assert_eq!("baca1a30-b6f1-470b-b68e-f79338020327", stream.entries[1].event_id);
}

fn test_stream_name() -> String {
    format!("task-{}", time::get_time().sec)
}
<|endoftext|>


<commit_before>use std::cell::{Ref, RefCell, RefMut};
use std::net;
use std::rc::Rc;

use bitflags::bitflags;

use crate::extensions::Extensions;
use crate::header::HeaderMap;
use crate::http::{header, Method, StatusCode, Uri, Version};

/// Represents various types of connection
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ConnectionType {
    /// Close connection after response
    Close,
    /// Keep connection alive after response
    KeepAlive,
    /// Connection is upgraded to different type
    Upgrade,
}

bitflags! {
    pub(crate) struct Flags: u8 {
        const CLOSE       = 0b0000_0001;
        const KEEP_ALIVE  = 0b0000_0010;
        const UPGRADE     = 0b0000_0100;
        const EXPECT      = 0b0000_1000;
        const NO_CHUNKING = 0b0001_0000;
        const CAMEL_CASE  = 0b0010_0000;
    }
}

#[doc(hidden)]
pub trait Head: Default + 'static {
    fn clear(&mut self);

    fn with_pool<F, R>(f: F) -> R
    where
        F: FnOnce(&MessagePool<Self>) -> R;
}

#[derive(Debug)]
pub struct RequestHead {
    pub uri: Uri,
    pub method: Method,
    pub version: Version,
    pub headers: HeaderMap,
    pub extensions: RefCell<Extensions>,
    pub peer_addr: Option<net::SocketAddr>,
    flags: Flags,
}

impl Default for RequestHead {
    fn default() -> RequestHead {
        RequestHead {
            uri: Uri::default(),
            method: Method::default(),
            version: Version::HTTP_11,
            headers: HeaderMap::with_capacity(16),
            flags: Flags::empty(),
            peer_addr: None,
            extensions: RefCell::new(Extensions::new()),
        }
    }
}

impl Head for RequestHead {
    fn clear(&mut self) {
        self.flags = Flags::empty();
        self.headers.clear();
        self.extensions.get_mut().clear();
    }

    fn with_pool<F, R>(f: F) -> R
    where
        F: FnOnce(&MessagePool<Self>) -> R,
    {
        REQUEST_POOL.with(|p| f(p))
    }
}

impl RequestHead {
    /// Message extensions
    #[inline]
    pub fn extensions(&self) -> Ref<'_, Extensions> {
        self.extensions.borrow()
    }

    /// Mutable reference to a the message's extensions
    #[inline]
    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
        self.extensions.borrow_mut()
    }

    /// Read the message headers.
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Mutable reference to the message headers.
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Is to uppercase headers with Camel-Case.
    /// Default is `false`
    #[inline]
    pub fn camel_case_headers(&self) -> bool {
        self.flags.contains(Flags::CAMEL_CASE)
    }

    /// Set `true` to send headers which are formatted as Camel-Case.
    #[inline]
    pub fn set_camel_case_headers(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::CAMEL_CASE);
        } else {
            self.flags.remove(Flags::CAMEL_CASE);
        }
    }

    #[inline]
    /// Set connection type of the message
    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
        match ctype {
            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
        }
    }

    #[inline]
    /// Connection type
    pub fn connection_type(&self) -> ConnectionType {
        if self.flags.contains(Flags::CLOSE) {
            ConnectionType::Close
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            ConnectionType::KeepAlive
        } else if self.flags.contains(Flags::UPGRADE) {
            ConnectionType::Upgrade
        } else if self.version < Version::HTTP_11 {
            ConnectionType::Close
        } else {
            ConnectionType::KeepAlive
        }
    }

    /// Connection upgrade status
    pub fn upgrade(&self) -> bool {
        if let Some(hdr) = self.headers().get(header::CONNECTION) {
            if let Ok(s) = hdr.to_str() {
                s.to_ascii_lowercase().contains("upgrade")
            } else {
                false
            }
        } else {
            false
        }
    }

    #[inline]
    /// Get response body chunking state
    pub fn chunked(&self) -> bool {
        !self.flags.contains(Flags::NO_CHUNKING)
    }

    #[inline]
    pub fn no_chunking(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::NO_CHUNKING);
        } else {
            self.flags.remove(Flags::NO_CHUNKING);
        }
    }

    #[inline]
    /// Request contains `EXPECT` header
    pub fn expect(&self) -> bool {
        self.flags.contains(Flags::EXPECT)
    }

    #[inline]
    pub(crate) fn set_expect(&mut self) {
        self.flags.insert(Flags::EXPECT);
    }
}

#[derive(Debug)]
pub enum RequestHeadType {
    Owned(RequestHead),
    Rc(Rc<RequestHead>, Option<HeaderMap>),
}

impl RequestHeadType {
    pub fn extra_headers(&self) -> Option<&HeaderMap> {
        match self {
            RequestHeadType::Owned(_) => None,
            RequestHeadType::Rc(_, headers) => headers.as_ref(),
        }
    }
}

impl AsRef<RequestHead> for RequestHeadType {
    fn as_ref(&self) -> &RequestHead {
        match self {
            RequestHeadType::Owned(head) => &head,
            RequestHeadType::Rc(head, _) => head.as_ref(),
        }
    }
}

impl From<RequestHead> for RequestHeadType {
    fn from(head: RequestHead) -> Self {
        RequestHeadType::Owned(head)
    }
}

#[derive(Debug)]
pub struct ResponseHead {
    pub version: Version,
    pub status: StatusCode,
    pub headers: HeaderMap,
    pub reason: Option<&'static str>,
    pub(crate) extensions: RefCell<Extensions>,
    flags: Flags,
}

impl ResponseHead {
    /// Create new instance of `ResponseHead` type
    #[inline]
    pub fn new(status: StatusCode) -> ResponseHead {
        ResponseHead {
            status,
            version: Version::default(),
            headers: HeaderMap::with_capacity(12),
            reason: None,
            flags: Flags::empty(),
            extensions: RefCell::new(Extensions::new()),
        }
    }

    /// Message extensions
    #[inline]
    pub fn extensions(&self) -> Ref<'_, Extensions> {
        self.extensions.borrow()
    }

    /// Mutable reference to a the message's extensions
    #[inline]
    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
        self.extensions.borrow_mut()
    }

    #[inline]
    /// Read the message headers.
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    #[inline]
    /// Mutable reference to the message headers.
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    #[inline]
    /// Set connection type of the message
    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
        match ctype {
            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
        }
    }

    #[inline]
    pub fn connection_type(&self) -> ConnectionType {
        if self.flags.contains(Flags::CLOSE) {
            ConnectionType::Close
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            ConnectionType::KeepAlive
        } else if self.flags.contains(Flags::UPGRADE) {
            ConnectionType::Upgrade
        } else if self.version < Version::HTTP_11 {
            ConnectionType::Close
        } else {
            ConnectionType::KeepAlive
        }
    }

    #[inline]
    /// Check if keep-alive is enabled
    pub fn keep_alive(&self) -> bool {
        self.connection_type() == ConnectionType::KeepAlive
    }

    #[inline]
    /// Check upgrade status of this message
    pub fn upgrade(&self) -> bool {
        self.connection_type() == ConnectionType::Upgrade
    }

    /// Get custom reason for the response
    #[inline]
    pub fn reason(&self) -> &str {
        if let Some(reason) = self.reason {
            reason
        } else {
            self.status
                .canonical_reason()
                .unwrap_or("<unknown status code>")
        }
    }

    #[inline]
    pub(crate) fn ctype(&self) -> Option<ConnectionType> {
        if self.flags.contains(Flags::CLOSE) {
            Some(ConnectionType::Close)
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            Some(ConnectionType::KeepAlive)
        } else if self.flags.contains(Flags::UPGRADE) {
            Some(ConnectionType::Upgrade)
        } else {
            None
        }
    }

    #[inline]
    /// Get response body chunking state
    pub fn chunked(&self) -> bool {
        !self.flags.contains(Flags::NO_CHUNKING)
    }

    #[inline]
    /// Set no chunking for payload
    pub fn no_chunking(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::NO_CHUNKING);
        } else {
            self.flags.remove(Flags::NO_CHUNKING);
        }
    }
}

pub struct Message<T: Head> {
    head: Rc<T>,
}

impl<T: Head> Message<T> {
    /// Get new message from the pool of objects
    pub fn new() -> Self {
        T::with_pool(|p| p.get_message())
    }
}

impl<T: Head> Clone for Message<T> {
    fn clone(&self) -> Self {
        Message {
            head: self.head.clone(),
        }
    }
}

impl<T: Head> std::ops::Deref for Message<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.head.as_ref()
    }
}

impl<T: Head> std::ops::DerefMut for Message<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        Rc::get_mut(&mut self.head).expect("Multiple copies exist")
    }
}

impl<T: Head> Drop for Message<T> {
    fn drop(&mut self) {
        if Rc::strong_count(&self.head) == 1 {
            T::with_pool(|p| p.release(self.head.clone()))
        }
    }
}

pub(crate) struct BoxedResponseHead {
    head: Option<Box<ResponseHead>>,
}

impl BoxedResponseHead {
    /// Get new message from the pool of objects
    pub fn new(status: StatusCode) -> Self {
        RESPONSE_POOL.with(|p| p.get_message(status))
    }

    pub(crate) fn take(&mut self) -> Self {
        BoxedResponseHead {
            head: self.head.take(),
        }
    }
}

impl std::ops::Deref for BoxedResponseHead {
    type Target = ResponseHead;

    fn deref(&self) -> &Self::Target {
        self.head.as_ref().unwrap()
    }
}

impl std::ops::DerefMut for BoxedResponseHead {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.head.as_mut().unwrap()
    }
}

impl Drop for BoxedResponseHead {
    fn drop(&mut self) {
        if let Some(head) = self.head.take() {
            RESPONSE_POOL.with(move |p| p.release(head))
        }
    }
}

#[doc(hidden)]
/// Request's objects pool
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);

#[doc(hidden)]
#[allow(clippy::vec_box)]
/// Request's objects pool
pub struct BoxedResponsePool(RefCell<Vec<Box<ResponseHead>>>);

thread_local!(static REQUEST_POOL: MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
thread_local!(static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create());

impl<T: Head> MessagePool<T> {
    fn create() -> MessagePool<T> {
        MessagePool(RefCell::new(Vec::with_capacity(128)))
    }

    /// Get message from the pool
    #[inline]
    fn get_message(&self) -> Message<T> {
        if let Some(mut msg) = self.0.borrow_mut().pop() {
            // Message is put in pool only when it's the last copy.
            // which means it's guaranteed to be unique when popped out.
            Rc::get_mut(&mut msg)
                .expect("Multiple copies exist")
                .clear();
            Message { head: msg }
        } else {
            Message {
                head: Rc::new(T::default()),
            }
        }
    }

    #[inline]
    /// Release request instance
    fn release(&self, msg: Rc<T>) {
        let v = &mut self.0.borrow_mut();
        if v.len() < 128 {
            v.push(msg);
        }
    }
}

impl BoxedResponsePool {
    fn create() -> BoxedResponsePool {
        BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
    }

    /// Get message from the pool
    #[inline]
    fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
        if let Some(mut head) = self.0.borrow_mut().pop() {
            head.reason = None;
            head.status = status;
            head.headers.clear();
            head.flags = Flags::empty();
            BoxedResponseHead { head: Some(head) }
        } else {
            BoxedResponseHead {
                head: Some(Box::new(ResponseHead::new(status))),
            }
        }
    }

    #[inline]
    /// Release request instance
    fn release(&self, mut msg: Box<ResponseHead>) {
        let v = &mut self.0.borrow_mut();
        if v.len() < 128 {
            msg.extensions.get_mut().clear();
            v.push(msg);
        }
    }
}
<commit_msg>optimize actix-http messages (#1914)<commit_after>use std::cell::{Ref, RefCell, RefMut};
use std::net;
use std::rc::Rc;

use bitflags::bitflags;

use crate::extensions::Extensions;
use crate::header::HeaderMap;
use crate::http::{header, Method, StatusCode, Uri, Version};

/// Represents various types of connection
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ConnectionType {
    /// Close connection after response
    Close,
    /// Keep connection alive after response
    KeepAlive,
    /// Connection is upgraded to different type
    Upgrade,
}

bitflags! {
    pub(crate) struct Flags: u8 {
        const CLOSE       = 0b0000_0001;
        const KEEP_ALIVE  = 0b0000_0010;
        const UPGRADE     = 0b0000_0100;
        const EXPECT      = 0b0000_1000;
        const NO_CHUNKING = 0b0001_0000;
        const CAMEL_CASE  = 0b0010_0000;
    }
}

#[doc(hidden)]
pub trait Head: Default + 'static {
    fn clear(&mut self);

    fn with_pool<F, R>(f: F) -> R
    where
        F: FnOnce(&MessagePool<Self>) -> R;
}

#[derive(Debug)]
pub struct RequestHead {
    pub uri: Uri,
    pub method: Method,
    pub version: Version,
    pub headers: HeaderMap,
    pub extensions: RefCell<Extensions>,
    pub peer_addr: Option<net::SocketAddr>,
    flags: Flags,
}

impl Default for RequestHead {
    fn default() -> RequestHead {
        RequestHead {
            uri: Uri::default(),
            method: Method::default(),
            version: Version::HTTP_11,
            headers: HeaderMap::with_capacity(16),
            flags: Flags::empty(),
            peer_addr: None,
            extensions: RefCell::new(Extensions::new()),
        }
    }
}

impl Head for RequestHead {
    fn clear(&mut self) {
        self.flags = Flags::empty();
        self.headers.clear();
        self.extensions.get_mut().clear();
    }

    fn with_pool<F, R>(f: F) -> R
    where
        F: FnOnce(&MessagePool<Self>) -> R,
    {
        REQUEST_POOL.with(|p| f(p))
    }
}

impl RequestHead {
    /// Message extensions
    #[inline]
    pub fn extensions(&self) -> Ref<'_, Extensions> {
        self.extensions.borrow()
    }

    /// Mutable reference to a the message's extensions
    #[inline]
    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
        self.extensions.borrow_mut()
    }

    /// Read the message headers.
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    /// Mutable reference to the message headers.
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    /// Is to uppercase headers with Camel-Case.
    /// Default is `false`
    #[inline]
    pub fn camel_case_headers(&self) -> bool {
        self.flags.contains(Flags::CAMEL_CASE)
    }

    /// Set `true` to send headers which are formatted as Camel-Case.
    #[inline]
    pub fn set_camel_case_headers(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::CAMEL_CASE);
        } else {
            self.flags.remove(Flags::CAMEL_CASE);
        }
    }

    #[inline]
    /// Set connection type of the message
    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
        match ctype {
            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
        }
    }

    #[inline]
    /// Connection type
    pub fn connection_type(&self) -> ConnectionType {
        if self.flags.contains(Flags::CLOSE) {
            ConnectionType::Close
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            ConnectionType::KeepAlive
        } else if self.flags.contains(Flags::UPGRADE) {
            ConnectionType::Upgrade
        } else if self.version < Version::HTTP_11 {
            ConnectionType::Close
        } else {
            ConnectionType::KeepAlive
        }
    }

    /// Connection upgrade status
    pub fn upgrade(&self) -> bool {
        if let Some(hdr) = self.headers().get(header::CONNECTION) {
            if let Ok(s) = hdr.to_str() {
                s.to_ascii_lowercase().contains("upgrade")
            } else {
                false
            }
        } else {
            false
        }
    }

    #[inline]
    /// Get response body chunking state
    pub fn chunked(&self) -> bool {
        !self.flags.contains(Flags::NO_CHUNKING)
    }

    #[inline]
    pub fn no_chunking(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::NO_CHUNKING);
        } else {
            self.flags.remove(Flags::NO_CHUNKING);
        }
    }

    #[inline]
    /// Request contains `EXPECT` header
    pub fn expect(&self) -> bool {
        self.flags.contains(Flags::EXPECT)
    }

    #[inline]
    pub(crate) fn set_expect(&mut self) {
        self.flags.insert(Flags::EXPECT);
    }
}

#[derive(Debug)]
pub enum RequestHeadType {
    Owned(RequestHead),
    Rc(Rc<RequestHead>, Option<HeaderMap>),
}

impl RequestHeadType {
    pub fn extra_headers(&self) -> Option<&HeaderMap> {
        match self {
            RequestHeadType::Owned(_) => None,
            RequestHeadType::Rc(_, headers) => headers.as_ref(),
        }
    }
}

impl AsRef<RequestHead> for RequestHeadType {
    fn as_ref(&self) -> &RequestHead {
        match self {
            RequestHeadType::Owned(head) => &head,
            RequestHeadType::Rc(head, _) => head.as_ref(),
        }
    }
}

impl From<RequestHead> for RequestHeadType {
    fn from(head: RequestHead) -> Self {
        RequestHeadType::Owned(head)
    }
}

#[derive(Debug)]
pub struct ResponseHead {
    pub version: Version,
    pub status: StatusCode,
    pub headers: HeaderMap,
    pub reason: Option<&'static str>,
    pub(crate) extensions: RefCell<Extensions>,
    flags: Flags,
}

impl ResponseHead {
    /// Create new instance of `ResponseHead` type
    #[inline]
    pub fn new(status: StatusCode) -> ResponseHead {
        ResponseHead {
            status,
            version: Version::default(),
            headers: HeaderMap::with_capacity(12),
            reason: None,
            flags: Flags::empty(),
            extensions: RefCell::new(Extensions::new()),
        }
    }

    /// Message extensions
    #[inline]
    pub fn extensions(&self) -> Ref<'_, Extensions> {
        self.extensions.borrow()
    }

    /// Mutable reference to a the message's extensions
    #[inline]
    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
        self.extensions.borrow_mut()
    }

    #[inline]
    /// Read the message headers.
    pub fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    #[inline]
    /// Mutable reference to the message headers.
    pub fn headers_mut(&mut self) -> &mut HeaderMap {
        &mut self.headers
    }

    #[inline]
    /// Set connection type of the message
    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
        match ctype {
            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
        }
    }

    #[inline]
    pub fn connection_type(&self) -> ConnectionType {
        if self.flags.contains(Flags::CLOSE) {
            ConnectionType::Close
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            ConnectionType::KeepAlive
        } else if self.flags.contains(Flags::UPGRADE) {
            ConnectionType::Upgrade
        } else if self.version < Version::HTTP_11 {
            ConnectionType::Close
        } else {
            ConnectionType::KeepAlive
        }
    }

    #[inline]
    /// Check if keep-alive is enabled
    pub fn keep_alive(&self) -> bool {
        self.connection_type() == ConnectionType::KeepAlive
    }

    #[inline]
    /// Check upgrade status of this message
    pub fn upgrade(&self) -> bool {
        self.connection_type() == ConnectionType::Upgrade
    }

    /// Get custom reason for the response
    #[inline]
    pub fn reason(&self) -> &str {
        if let Some(reason) = self.reason {
            reason
        } else {
            self.status
                .canonical_reason()
                .unwrap_or("<unknown status code>")
        }
    }

    #[inline]
    pub(crate) fn ctype(&self) -> Option<ConnectionType> {
        if self.flags.contains(Flags::CLOSE) {
            Some(ConnectionType::Close)
        } else if self.flags.contains(Flags::KEEP_ALIVE) {
            Some(ConnectionType::KeepAlive)
        } else if self.flags.contains(Flags::UPGRADE) {
            Some(ConnectionType::Upgrade)
        } else {
            None
        }
    }

    #[inline]
    /// Get response body chunking state
    pub fn chunked(&self) -> bool {
        !self.flags.contains(Flags::NO_CHUNKING)
    }

    #[inline]
    /// Set no chunking for payload
    pub fn no_chunking(&mut self, val: bool) {
        if val {
            self.flags.insert(Flags::NO_CHUNKING);
        } else {
            self.flags.remove(Flags::NO_CHUNKING);
        }
    }
}

pub struct Message<T: Head> {
    // Rc here should not be cloned by anyone.
    // It's used to reuse allocation of T and no shared ownership is allowed.
    head: Rc<T>,
}

impl<T: Head> Message<T> {
    /// Get new message from the pool of objects
    pub fn new() -> Self {
        T::with_pool(|p| p.get_message())
    }
}

impl<T: Head> std::ops::Deref for Message<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.head.as_ref()
    }
}

impl<T: Head> std::ops::DerefMut for Message<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        Rc::get_mut(&mut self.head).expect("Multiple copies exist")
    }
}

impl<T: Head> Drop for Message<T> {
    fn drop(&mut self) {
        T::with_pool(|p| p.release(self.head.clone()))
    }
}

pub(crate) struct BoxedResponseHead {
    head: Option<Box<ResponseHead>>,
}

impl BoxedResponseHead {
    /// Get new message from the pool of objects
    pub fn new(status: StatusCode) -> Self {
        RESPONSE_POOL.with(|p| p.get_message(status))
    }

    pub(crate) fn take(&mut self) -> Self {
        BoxedResponseHead {
            head: self.head.take(),
        }
    }
}

impl std::ops::Deref for BoxedResponseHead {
    type Target = ResponseHead;

    fn deref(&self) -> &Self::Target {
        self.head.as_ref().unwrap()
    }
}

impl std::ops::DerefMut for BoxedResponseHead {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.head.as_mut().unwrap()
    }
}

impl Drop for BoxedResponseHead {
    fn drop(&mut self) {
        if let Some(head) = self.head.take() {
            RESPONSE_POOL.with(move |p| p.release(head))
        }
    }
}

#[doc(hidden)]
/// Request's objects pool
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);

#[doc(hidden)]
#[allow(clippy::vec_box)]
/// Request's objects pool
pub struct BoxedResponsePool(RefCell<Vec<Box<ResponseHead>>>);

thread_local!(static REQUEST_POOL: MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
thread_local!(static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create());

impl<T: Head> MessagePool<T> {
    fn create() -> MessagePool<T> {
        MessagePool(RefCell::new(Vec::with_capacity(128)))
    }

    /// Get message from the pool
    #[inline]
    fn get_message(&self) -> Message<T> {
        if let Some(mut msg) = self.0.borrow_mut().pop() {
            // Message is put in pool only when it's the last copy.
            // which means it's guaranteed to be unique when popped out.
            Rc::get_mut(&mut msg)
                .expect("Multiple copies exist")
                .clear();
            Message { head: msg }
        } else {
            Message {
                head: Rc::new(T::default()),
            }
        }
    }

    #[inline]
    /// Release request instance
    fn release(&self, msg: Rc<T>) {
        let v = &mut self.0.borrow_mut();
        if v.len() < 128 {
            v.push(msg);
        }
    }
}

impl BoxedResponsePool {
    fn create() -> BoxedResponsePool {
        BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
    }

    /// Get message from the pool
    #[inline]
    fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
        if let Some(mut head) = self.0.borrow_mut().pop() {
            head.reason = None;
            head.status = status;
            head.headers.clear();
            head.flags = Flags::empty();
            BoxedResponseHead { head: Some(head) }
        } else {
            BoxedResponseHead {
                head: Some(Box::new(ResponseHead::new(status))),
            }
        }
    }

    #[inline]
    /// Release request instance
    fn release(&self, mut msg: Box<ResponseHead>) {
        let v = &mut self.0.borrow_mut();
        if v.len() < 128 {
            msg.extensions.get_mut().clear();
            v.push(msg);
        }
    }
}
<|endoftext|>


<commit_before>
//! Back-end agnostic controller events.

use {Event, Input, Motion};

/// Components of a controller button event. Not guaranteed consistent across
/// backends.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
pub struct ControllerButton {
    /// Which controller was the button on.
    pub id: i32,
    /// Which button was pressed.
    pub button: u8,
}

impl ControllerButton {
    /// Create a new ControllerButton object. Intended for use by backends when
    /// emitting events.
    pub fn new(id: i32, button: u8) -> Self {
        ControllerButton {
            id: id,
            button: button,
        }
    }
}

/// Components of a controller hat move event (d-Pad).
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
pub struct ControllerHat {
  /// Which Controller was the button on.
  pub id: i32,
  /// Which button was pressed.
  pub state: ::HatState,
  /// Which hat on the controller was changed
  pub which: u8,
}

impl ControllerHat {
    /// Create a new ControllerButton object. Intended for use by backends when
    /// emitting events.
  pub fn new(id: i32, which: u8, state: ::HatState) -> Self {
    ControllerHat {
      id, state, which,
    }
  }
}

/// Components of a controller axis move event. Not guaranteed consistent across
/// backends.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub struct ControllerAxisArgs {
    /// Which controller moved.
    pub id: i32,
    /// The axis that moved.
    pub axis: u8,
    /// Position of the controller. Usually [-1.0, 1.0], though backends may use
    /// a different range for various devices.
    pub position: f64,
}

impl ControllerAxisArgs {
    /// Create a new ControllerAxisArgs object. Intended for use by backends when
    /// emitting events.
    pub fn new(id: i32, axis: u8, position: f64) -> Self {
        ControllerAxisArgs {
            id: id,
            axis: axis,
            position: position,
        }
    }
}

/// The position of a controller axis changed.
pub trait ControllerAxisEvent: Sized {
    /// Creates a controller axis event.
    fn from_controller_axis_args(args: ControllerAxisArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a controller axis event.
    fn controller_axis<U, F>(&self, f: F) -> Option<U> where F: FnMut(ControllerAxisArgs) -> U;
    /// Returns controller axis arguments.
    fn controller_axis_args(&self) -> Option<ControllerAxisArgs> {
        self.controller_axis(|args| args)
    }
}

impl ControllerAxisEvent for Event {
    fn from_controller_axis_args(args: ControllerAxisArgs, _old_event: &Self) -> Option<Self> {
        Some(Event::Input(Input::Move(Motion::ControllerAxis(args))))
    }

    fn controller_axis<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(ControllerAxisArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::ControllerAxis(args))) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_controller_axis() {
        let e: Event = ControllerAxisArgs::new(0, 1, 0.9).into();
        let a: Option<Event> =
            ControllerAxisEvent::from_controller_axis_args(ControllerAxisArgs::new(0, 1, 0.9), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .controller_axis(|cnt| {
                ControllerAxisEvent::from_controller_axis_args(
                ControllerAxisArgs::new(cnt.id, cnt.axis, cnt.position),
                a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<commit_msg>Minor Formatting fix<commit_after>
//! Back-end agnostic controller events.

use {Event, Input, Motion};

/// Components of a controller button event. Not guaranteed consistent across
/// backends.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
pub struct ControllerButton {
    /// Which controller was the button on.
    pub id: i32,
    /// Which button was pressed.
    pub button: u8,
}

impl ControllerButton {
    /// Create a new ControllerButton object. Intended for use by backends when
    /// emitting events.
    pub fn new(id: i32, button: u8) -> Self {
        ControllerButton {
            id: id,
            button: button,
        }
    }
}

/// Components of a controller hat move event (d-Pad).
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
pub struct ControllerHat {
  /// Which Controller was the button on.
  pub id: i32,
  /// Which button was pressed.
  pub state: ::HatState,
  /// Which hat on the controller was changed
  pub which: u8,
}

impl ControllerHat {
  /// Create a new ControllerButton object. Intended for use by backends when
  /// emitting events.
  pub fn new(id: i32, which: u8, state: ::HatState) -> Self {
    ControllerHat {
      id, state, which,
    }
  }
}

/// Components of a controller axis move event. Not guaranteed consistent across
/// backends.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub struct ControllerAxisArgs {
    /// Which controller moved.
    pub id: i32,
    /// The axis that moved.
    pub axis: u8,
    /// Position of the controller. Usually [-1.0, 1.0], though backends may use
    /// a different range for various devices.
    pub position: f64,
}

impl ControllerAxisArgs {
    /// Create a new ControllerAxisArgs object. Intended for use by backends when
    /// emitting events.
    pub fn new(id: i32, axis: u8, position: f64) -> Self {
        ControllerAxisArgs {
            id: id,
            axis: axis,
            position: position,
        }
    }
}

/// The position of a controller axis changed.
pub trait ControllerAxisEvent: Sized {
    /// Creates a controller axis event.
    fn from_controller_axis_args(args: ControllerAxisArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a controller axis event.
    fn controller_axis<U, F>(&self, f: F) -> Option<U> where F: FnMut(ControllerAxisArgs) -> U;
    /// Returns controller axis arguments.
    fn controller_axis_args(&self) -> Option<ControllerAxisArgs> {
        self.controller_axis(|args| args)
    }
}

impl ControllerAxisEvent for Event {
    fn from_controller_axis_args(args: ControllerAxisArgs, _old_event: &Self) -> Option<Self> {
        Some(Event::Input(Input::Move(Motion::ControllerAxis(args))))
    }

    fn controller_axis<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(ControllerAxisArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::ControllerAxis(args))) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_controller_axis() {
        let e: Event = ControllerAxisArgs::new(0, 1, 0.9).into();
        let a: Option<Event> =
            ControllerAxisEvent::from_controller_axis_args(ControllerAxisArgs::new(0, 1, 0.9), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .controller_axis(|cnt| {
                ControllerAxisEvent::from_controller_axis_args(
                ControllerAxisArgs::new(cnt.id, cnt.axis, cnt.position),
                a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<|endoftext|>


<commit_before>pub mod bridge;

use crate::homectl_core::{
    device::{Device, DeviceKind, Light},
    events::{Message, TxEventChannel},
    integration::{Integration, IntegrationId},
};
use async_trait::async_trait;
use bridge::{BridgeLight, BridgeLights, BridgeState};
use palette::{Hsl, IntoColor, Lch};
use serde::Deserialize;
use std::{error::Error, time::Duration};
use tokio::time::{interval_at, Instant};

#[derive(Clone, Debug, Deserialize)]
pub struct HueConfig {
    addr: String,
    username: String,
    poll_rate_sensors: u64,
    poll_rate_lights: u64,
}

pub struct Hue {
    id: String,
    devices: Vec<Device>,
    sender: TxEventChannel,
    config: HueConfig,
    bridge_state: Option<BridgeState>,
}

#[async_trait]
impl Integration for Hue {
    fn new(id: &IntegrationId, config: &config::Value, sender: TxEventChannel) -> Self {
        Hue {
            id: id.clone(),
            devices: Vec::new(),
            config: config.clone().try_into().unwrap(),
            sender,
            bridge_state: None,
        }
    }

    async fn register(&mut self) -> Result<(), Box<dyn Error>> {
        let bridge_state: BridgeState = reqwest::get(&format!(
            "http://{}/api/{}",
            self.config.addr, self.config.username
        ))
        .await?
        .json()
        .await?;

        self.bridge_state = Some(bridge_state);

        println!("{:#?}", self.bridge_state);
        println!("registered hue integration");

        Ok(())
    }

    async fn start(&mut self) -> Result<(), Box<dyn Error>> {
        println!("started hue integration");

        // FIXME: how to do this in a not stupid way
        let config1 = self.config.clone();
        let config2 = self.config.clone();
        let integration_id1 = self.id.clone();
        let integration_id2 = self.id.clone();
        let sender1 = self.sender.clone();
        let sender2 = self.sender.clone();

        tokio::spawn(async { poll_sensors(config1, integration_id1, sender1).await });
        tokio::spawn(async { poll_lights(config2, integration_id2, sender2).await });

        Ok(())
    }

    fn set_device_state(&mut self, device: Device) {
        println!("hue: would set_device_state {:?}", device);
    }
}

async fn poll_sensors(config: HueConfig, integration_id: IntegrationId, sender: TxEventChannel) {
    let poll_rate = Duration::from_millis(config.poll_rate_sensors);
    let start = Instant::now() + poll_rate;
    let mut interval = interval_at(start, poll_rate);

    loop {
        interval.tick().await;
        println!("would poll sensors");

        let kind = Light {
            power: true,
            brightness: Some(1.0),
            color: None,
        };
        sender
            .send(Message::HandleDeviceUpdate(Device {
                id: String::from("test"),
                name: String::from("Test sensor"),
                integration_id: integration_id.clone(),
                scene: None,
                kind: DeviceKind::Light(kind),
            }))
            .unwrap();
    }
}

fn hue_to_palette(bridge_light: BridgeLight) -> Option<Lch> {
    let hue: f32 = bridge_light.state.hue? as f32;
    let saturation: f32 = bridge_light.state.sat? as f32;
    let lightness: f32 = bridge_light.state.bri? as f32;

    let hsl = Hsl::new(
        (hue / 65536.0) * 360.0,
        saturation / 254.0,
        lightness / 254.0,
    );
    let lch: Lch = hsl.into_lch();

    Some(lch)
}

async fn do_refresh_lights(
    config: HueConfig,
    integration_id: IntegrationId,
    sender: TxEventChannel,
) {
    let bridge_lights: BridgeLights = reqwest::get(&format!(
        "http://{}/api/{}/lights",
        config.addr, config.username
    ))
    .await
    .unwrap() // FIXME: no .unwrap(), why doesn't `.await?` work here
    .json()
    .await
    .unwrap();

    for (light_id, bridge_light) in bridge_lights {
        let kind = Light {
            power: bridge_light.state.on,
            brightness: None,
            color: hue_to_palette(bridge_light.clone()),
        };
        sender
            .send(Message::HandleDeviceUpdate(Device {
                id: light_id,
                name: bridge_light.name.clone(),
                integration_id: integration_id.clone(),
                scene: None,
                kind: DeviceKind::Light(kind),
            }))
            .unwrap();
    }
}

async fn poll_lights(config: HueConfig, integration_id: IntegrationId, sender: TxEventChannel) {
    let poll_rate = Duration::from_millis(config.poll_rate_lights);
    let start = Instant::now() + poll_rate;
    let mut interval = interval_at(start, poll_rate);

    loop {
        interval.tick().await;
        println!("would poll lights");

        let sender = sender.clone();
        do_refresh_lights(config.clone(), integration_id.clone(), sender).await;
    }
}
<commit_msg>get rid of .unwrap() call on request<commit_after>pub mod bridge;

use crate::homectl_core::{
    device::{Device, DeviceKind, Light},
    events::{Message, TxEventChannel},
    integration::{Integration, IntegrationId},
};
use async_trait::async_trait;
use bridge::{BridgeLight, BridgeLights, BridgeState};
use palette::{Hsl, IntoColor, Lch};
use serde::Deserialize;
use std::{error::Error, time::Duration};
use tokio::time::{interval_at, Instant};

#[derive(Clone, Debug, Deserialize)]
pub struct HueConfig {
    addr: String,
    username: String,
    poll_rate_sensors: u64,
    poll_rate_lights: u64,
}

pub struct Hue {
    id: String,
    devices: Vec<Device>,
    sender: TxEventChannel,
    config: HueConfig,
    bridge_state: Option<BridgeState>,
}

#[async_trait]
impl Integration for Hue {
    fn new(id: &IntegrationId, config: &config::Value, sender: TxEventChannel) -> Self {
        Hue {
            id: id.clone(),
            devices: Vec::new(),
            config: config.clone().try_into().unwrap(),
            sender,
            bridge_state: None,
        }
    }

    async fn register(&mut self) -> Result<(), Box<dyn Error>> {
        let bridge_state: BridgeState = reqwest::get(&format!(
            "http://{}/api/{}",
            self.config.addr, self.config.username
        ))
        .await?
        .json()
        .await?;

        self.bridge_state = Some(bridge_state);

        println!("{:#?}", self.bridge_state);
        println!("registered hue integration");

        Ok(())
    }

    async fn start(&mut self) -> Result<(), Box<dyn Error>> {
        println!("started hue integration");

        // FIXME: how to do this in a not stupid way
        let config1 = self.config.clone();
        let config2 = self.config.clone();
        let integration_id1 = self.id.clone();
        let integration_id2 = self.id.clone();
        let sender1 = self.sender.clone();
        let sender2 = self.sender.clone();

        tokio::spawn(async { poll_sensors(config1, integration_id1, sender1).await });
        tokio::spawn(async { poll_lights(config2, integration_id2, sender2).await });

        Ok(())
    }

    fn set_device_state(&mut self, device: Device) {
        println!("hue: would set_device_state {:?}", device);
    }
}

async fn poll_sensors(config: HueConfig, integration_id: IntegrationId, sender: TxEventChannel) {
    let poll_rate = Duration::from_millis(config.poll_rate_sensors);
    let start = Instant::now() + poll_rate;
    let mut interval = interval_at(start, poll_rate);

    loop {
        interval.tick().await;
        println!("would poll sensors");

        let kind = Light {
            power: true,
            brightness: Some(1.0),
            color: None,
        };
        sender
            .send(Message::HandleDeviceUpdate(Device {
                id: String::from("test"),
                name: String::from("Test sensor"),
                integration_id: integration_id.clone(),
                scene: None,
                kind: DeviceKind::Light(kind),
            }))
            .unwrap();
    }
}

fn hue_to_palette(bridge_light: BridgeLight) -> Option<Lch> {
    let hue: f32 = bridge_light.state.hue? as f32;
    let saturation: f32 = bridge_light.state.sat? as f32;
    let lightness: f32 = bridge_light.state.bri? as f32;

    let hsl = Hsl::new(
        (hue / 65536.0) * 360.0,
        saturation / 254.0,
        lightness / 254.0,
    );
    let lch: Lch = hsl.into_lch();

    Some(lch)
}

async fn do_refresh_lights(
    config: HueConfig,
    integration_id: IntegrationId,
    sender: TxEventChannel,
) -> Result<(), Box<dyn Error>> {
    let bridge_lights: BridgeLights = reqwest::get(&format!(
        "http://{}/api/{}/lights",
        config.addr, config.username
    ))
    .await?
    .json()
    .await?;

    for (light_id, bridge_light) in bridge_lights {
        let kind = Light {
            power: bridge_light.state.on,
            brightness: None,
            color: hue_to_palette(bridge_light.clone()),
        };
        sender
            .send(Message::HandleDeviceUpdate(Device {
                id: light_id,
                name: bridge_light.name.clone(),
                integration_id: integration_id.clone(),
                scene: None,
                kind: DeviceKind::Light(kind),
            }))
            .unwrap();
    }

    Ok(())
}

async fn poll_lights(config: HueConfig, integration_id: IntegrationId, sender: TxEventChannel) {
    let poll_rate = Duration::from_millis(config.poll_rate_lights);
    let start = Instant::now() + poll_rate;
    let mut interval = interval_at(start, poll_rate);

    loop {
        interval.tick().await;
        println!("would poll lights");

        let sender = sender.clone();
        let result = do_refresh_lights(config.clone(), integration_id.clone(), sender).await;

        match result {
            Ok(()) => {}
            Err(e) => println!("Error while polling lights: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>/*!
`ed25519`, a signature scheme specified in
[Ed25519](http://ed25519.cr.yp.to/). This function is conjectured to meet the
standard notion of unforgeability for a public-key signature scheme under
chosen-message attacks.
*/
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate serialize;
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;

#[link(name = "sodium")]
extern {
    fn crypto_sign_ed25519_keypair(pk: *mut u8,
                                   sk: *mut u8) -> c_int;
    fn crypto_sign_ed25519_seed_keypair(pk: *mut u8,
                                        sk: *mut u8,
                                        seed: *const u8) -> c_int;
    fn crypto_sign_ed25519(sm: *mut u8,
                           smlen: *mut c_ulonglong,
                           m: *const u8,
                           mlen: c_ulonglong,
                           sk: *const u8) -> c_int;
    fn crypto_sign_ed25519_open(m: *mut u8,
                                mlen: *mut c_ulonglong,
                                sm: *const u8,
                                smlen: c_ulonglong,
                                pk: *const u8) -> c_int;
}

pub const SEEDBYTES: uint = 32;
pub const SECRETKEYBYTES: uint = 64;
pub const PUBLICKEYBYTES: uint = 32;
pub const SIGNATUREBYTES: uint = 64;

/**
 * `Seed` that can be used for keypair generation
 *
 * The `Seed` is used by `keypair_from_seed()` to generate
 * a secret and public signature key.
 *
 * When a `Seed` goes out of scope its contents
 * will be zeroed out
 */
pub struct Seed(pub [u8, ..SEEDBYTES]);

newtype_drop!(Seed)
newtype_clone!(Seed)

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey(pub [u8, ..SECRETKEYBYTES]);

newtype_drop!(SecretKey)
newtype_clone!(SecretKey)

/**
 * `PublicKey` for signatures
 */
pub struct PublicKey(pub [u8, ..PUBLICKEYBYTES]);

newtype_clone!(PublicKey)

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_keypair() -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `keypair_from_seed()` computes a secret key and a corresponding public key
 * from a `Seed`.
 */
pub fn keypair_from_seed(&Seed(seed): &Seed) -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_seed_keypair(pk.as_mut_ptr(),
                                         sk.as_mut_ptr(),
                                         seed.as_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
pub fn sign(m: &[u8],
            &SecretKey(sk): &SecretKey) -> Vec<u8> {
    unsafe {
        let mut sm = Vec::from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_ed25519(sm.as_mut_ptr(),
                            &mut smlen,
                            m.as_ptr(),
                            m.len() as c_ulonglong,
                            sk.as_ptr());
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
pub fn verify(sm: &[u8],
              &PublicKey(pk): &PublicKey) -> Option<Vec<u8>> {
    unsafe {
        let mut m = Vec::from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_ed25519_open(m.as_mut_ptr(),
                                    &mut mlen,
                                    sm.as_ptr(),
                                    sm.len() as c_ulonglong,
                                    pk.as_ptr()) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for i in range(0, 256u) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i);
        let sm = sign(m.as_slice(), &sk);
        let m2 = verify(sm.as_slice(), &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32u) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i);
        let mut smv = sign(m.as_slice(), &sk);
        let sm = smv.as_mut_slice();
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_sign_verify_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 256u) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i);
        let sm = sign(m.as_slice(), &sk);
        let m2 = verify(sm.as_slice(), &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 32u) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i);
        let mut smv = sign(m.as_slice(), &sk);
        let sm = smv.as_mut_slice();
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_vectors() {
    // test vectors from the Python implementation
    // form the [Ed25519 Homepage](http://ed25519.cr.yp.to/software.html)
    use self::serialize::hex::{FromHex, ToHex};
    use std::io::BufferedReader;
    use std::io::File;
    use std::path::Path;

    let p = &Path::new("testvectors/ed25519.input");
    let mut r = BufferedReader::new(File::open(p).unwrap());
    loop {
        let line = match r.read_line() {
            Err(_) => break,
            Ok(line) => line
        };
        let mut x = line.as_slice().split(':');
        let x0 = x.next().unwrap();
        let x1 = x.next().unwrap();
        let x2 = x.next().unwrap();
        let x3 = x.next().unwrap();
        let seed_bytes = x0.slice(0, 64).from_hex().unwrap();
        assert!(seed_bytes.len() == SEEDBYTES);
        let mut seedbuf = [0u8, ..SEEDBYTES];
        for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
            *s = *b
        }
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = x2.from_hex().unwrap();
        let sm = sign(m.as_slice(), &sk);
        verify(sm.as_slice(), &pk).unwrap();
        let PublicKey(pkbuf) = pk;
        assert!(x1 == pkbuf.as_slice().to_hex().as_slice());
        assert!(x3 == sm.as_slice().to_hex().as_slice());
    }
}

#[cfg(test)]
const BENCH_SIZES: [uint, ..14] = [0, 1, 2, 4, 8, 16, 32, 64,
                                   128, 256, 512, 1024, 2048, 4096];

#[bench]
fn bench_sign(b: &mut test::Bencher) {
    use randombytes::randombytes;
    let (_, sk) = gen_keypair();
    let ms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
        randombytes(*s)
    }).collect();
    b.iter(|| {
        for m in ms.iter() {
            sign(m.as_slice(), &sk);
        }
    });
}

#[bench]
fn bench_verify(b: &mut test::Bencher) {
    use randombytes::randombytes;
    let (pk, sk) = gen_keypair();
    let sms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
        let m = randombytes(*s);
        sign(m.as_slice(), &sk)
    }).collect();
    b.iter(|| {
        for sm in sms.iter() {
            verify(sm.as_slice(), &pk);
        }
    });
}
<commit_msg>Fixed spelling in comment<commit_after>/*!
`ed25519`, a signature scheme specified in
[Ed25519](http://ed25519.cr.yp.to/). This function is conjectured to meet the
standard notion of unforgeability for a public-key signature scheme under
chosen-message attacks.
*/
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate serialize;
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;

#[link(name = "sodium")]
extern {
    fn crypto_sign_ed25519_keypair(pk: *mut u8,
                                   sk: *mut u8) -> c_int;
    fn crypto_sign_ed25519_seed_keypair(pk: *mut u8,
                                        sk: *mut u8,
                                        seed: *const u8) -> c_int;
    fn crypto_sign_ed25519(sm: *mut u8,
                           smlen: *mut c_ulonglong,
                           m: *const u8,
                           mlen: c_ulonglong,
                           sk: *const u8) -> c_int;
    fn crypto_sign_ed25519_open(m: *mut u8,
                                mlen: *mut c_ulonglong,
                                sm: *const u8,
                                smlen: c_ulonglong,
                                pk: *const u8) -> c_int;
}

pub const SEEDBYTES: uint = 32;
pub const SECRETKEYBYTES: uint = 64;
pub const PUBLICKEYBYTES: uint = 32;
pub const SIGNATUREBYTES: uint = 64;

/**
 * `Seed` that can be used for keypair generation
 *
 * The `Seed` is used by `keypair_from_seed()` to generate
 * a secret and public signature key.
 *
 * When a `Seed` goes out of scope its contents
 * will be zeroed out
 */
pub struct Seed(pub [u8, ..SEEDBYTES]);

newtype_drop!(Seed)
newtype_clone!(Seed)

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey(pub [u8, ..SECRETKEYBYTES]);

newtype_drop!(SecretKey)
newtype_clone!(SecretKey)

/**
 * `PublicKey` for signatures
 */
pub struct PublicKey(pub [u8, ..PUBLICKEYBYTES]);

newtype_clone!(PublicKey)

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_keypair() -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `keypair_from_seed()` computes a secret key and a corresponding public key
 * from a `Seed`.
 */
pub fn keypair_from_seed(&Seed(seed): &Seed) -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_seed_keypair(pk.as_mut_ptr(),
                                         sk.as_mut_ptr(),
                                         seed.as_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
pub fn sign(m: &[u8],
            &SecretKey(sk): &SecretKey) -> Vec<u8> {
    unsafe {
        let mut sm = Vec::from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_ed25519(sm.as_mut_ptr(),
                            &mut smlen,
                            m.as_ptr(),
                            m.len() as c_ulonglong,
                            sk.as_ptr());
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
pub fn verify(sm: &[u8],
              &PublicKey(pk): &PublicKey) -> Option<Vec<u8>> {
    unsafe {
        let mut m = Vec::from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_ed25519_open(m.as_mut_ptr(),
                                    &mut mlen,
                                    sm.as_ptr(),
                                    sm.len() as c_ulonglong,
                                    pk.as_ptr()) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for i in range(0, 256u) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i);
        let sm = sign(m.as_slice(), &sk);
        let m2 = verify(sm.as_slice(), &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32u) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i);
        let mut smv = sign(m.as_slice(), &sk);
        let sm = smv.as_mut_slice();
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_sign_verify_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 256u) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i);
        let sm = sign(m.as_slice(), &sk);
        let m2 = verify(sm.as_slice(), &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 32u) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i);
        let mut smv = sign(m.as_slice(), &sk);
        let sm = smv.as_mut_slice();
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_vectors() {
    // test vectors from the Python implementation
    // from the [Ed25519 Homepage](http://ed25519.cr.yp.to/software.html)
    use self::serialize::hex::{FromHex, ToHex};
    use std::io::BufferedReader;
    use std::io::File;
    use std::path::Path;

    let p = &Path::new("testvectors/ed25519.input");
    let mut r = BufferedReader::new(File::open(p).unwrap());
    loop {
        let line = match r.read_line() {
            Err(_) => break,
            Ok(line) => line
        };
        let mut x = line.as_slice().split(':');
        let x0 = x.next().unwrap();
        let x1 = x.next().unwrap();
        let x2 = x.next().unwrap();
        let x3 = x.next().unwrap();
        let seed_bytes = x0.slice(0, 64).from_hex().unwrap();
        assert!(seed_bytes.len() == SEEDBYTES);
        let mut seedbuf = [0u8, ..SEEDBYTES];
        for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
            *s = *b
        }
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = x2.from_hex().unwrap();
        let sm = sign(m.as_slice(), &sk);
        verify(sm.as_slice(), &pk).unwrap();
        let PublicKey(pkbuf) = pk;
        assert!(x1 == pkbuf.as_slice().to_hex().as_slice());
        assert!(x3 == sm.as_slice().to_hex().as_slice());
    }
}

#[cfg(test)]
const BENCH_SIZES: [uint, ..14] = [0, 1, 2, 4, 8, 16, 32, 64,
                                   128, 256, 512, 1024, 2048, 4096];

#[bench]
fn bench_sign(b: &mut test::Bencher) {
    use randombytes::randombytes;
    let (_, sk) = gen_keypair();
    let ms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
        randombytes(*s)
    }).collect();
    b.iter(|| {
        for m in ms.iter() {
            sign(m.as_slice(), &sk);
        }
    });
}

#[bench]
fn bench_verify(b: &mut test::Bencher) {
    use randombytes::randombytes;
    let (pk, sk) = gen_keypair();
    let sms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
        let m = randombytes(*s);
        sign(m.as_slice(), &sk)
    }).collect();
    b.iter(|| {
        for sm in sms.iter() {
            verify(sm.as_slice(), &pk);
        }
    });
}
<|endoftext|>


<commit_before>#![crate_type = "dylib"]

extern crate libc;

use libc::{c_char,c_int};
use std::ffi::CStr;
use std::str;
//use std::Vec;

fn parse_c_str(c_buf:*const c_char) -> Option<String> {
    let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
    let buf: &[u8] = c_str.to_bytes();
    match str::from_utf8(buf) {
        Ok(str_slice) => Some(str_slice.to_string()),
        Err(_) => None
    }
}

#[no_mangle]
pub extern fn main(argc:c_int, argv:*const *const c_char) -> i32 {
    let mut result:Vec<String> = Vec::new();
    for idx in 0..(argc) {
        let arg = unsafe {parse_c_str(*argv.offset(idx as isize))};
        match arg {
            Some(x) => result.push(x),
            _ => {}
        }
    }
    println!("Hello world from Rust (argc={})\n", argc);
    let mut idx = 0;
    for x in result {
        println!("argv[{}]={}\n", idx, x);
        idx+= 1;
    }
    1
}
<commit_msg>Refactored out code that parses an array of C strings.<commit_after>#![crate_type = "dylib"]

extern crate libc;

use libc::{c_char,c_int};
use std::ffi::CStr;
use std::str;
//use std::Vec;

fn parse_c_str(c_buf:*const c_char) -> Option<String> {
    let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
    let buf: &[u8] = c_str.to_bytes();
    match str::from_utf8(buf) {
        Ok(str_slice) => Some(str_slice.to_string()),
        Err(_) => None
    }
}

fn parse_c_str_array(argc:c_int, argv:*const *const c_char) -> Option<Vec<String>> {
    let mut result:Vec<String> = Vec::new();
    for idx in 0..(argc) {
        let arg = unsafe {parse_c_str(*argv.offset(idx as isize))};
        match arg {
            Some(x) => result.push(x),
            _ => return None
        }
    }
    Some(result)
}

#[no_mangle]
pub extern fn main(argc:c_int, argv:*const *const c_char) -> i32 {
    println!("Hello world from Rust (argc={})\n", argc);
    let mut idx = 0;
    for x in parse_c_str_array(argc, argv).unwrap() {
        println!("argv[{}]={}\n", idx, x);
        idx+= 1;
    }
    1
}
<|endoftext|>


<commit_before>//! Implements the SSA construction algorithm described in
//! "Simple and Efficient Construction of Static Single Assignment Form"

use std::collections::HashMap;
use petgraph::graph::NodeIndex;
use frontend::structs::LRegInfo;
use middle::cfg::NodeData as CFGNodeData;
use middle::cfg::EdgeType as CFGEdgeType;
use middle::cfg::{CFG, BasicBlock};
use middle::ssa::{BBInfo, SSA, SSAMod, ValueType};
use middle::ir::{MVal, MInst, MOpcode, MValType};
use middle::phiplacement::PhiPlacer;
use middle::regfile::SubRegisterFile;
use middle::dce;

pub type VarId = usize;

pub struct SSAConstruction<'a, T>
where T: Clone + SSAMod<BBInfo=BBInfo> + 'a {
	pub phiplacer: PhiPlacer<'a, T>,
	pub regfile:   SubRegisterFile,
	pub temps:     HashMap<String, T::ValueRef>,
}

impl<'a, T> SSAConstruction<'a, T>
where T: 'a + Clone +
SSAMod<BBInfo=BBInfo, ValueRef=NodeIndex, ActionRef=NodeIndex> {
	pub fn new(ssa: &'a mut T, reg_info: &LRegInfo) -> SSAConstruction<'a, T> {
		let mut sc = SSAConstruction {
			phiplacer: PhiPlacer::new(ssa),
			regfile:   SubRegisterFile::new(reg_info),
			temps:     HashMap::new(),
		};
		sc.phiplacer.add_variables(vec![
								   ValueType::Integer{width: 64}, // cur
								   ValueType::Integer{width: 64}  // old
		]);
		// make the following a method of regfile?
		sc.phiplacer.add_variables(sc.regfile.whole_registers.clone());
		sc
	}

	pub fn run(&mut self, cfg: &CFG) {
		let mut blocks = Vec::<T::ActionRef>::with_capacity(cfg.g.node_count());
		let bb_iter = cfg.bbs.iter();

		for _ in 0..cfg.g.node_count() {
			blocks.push(self.phiplacer.ssa.invalid_action());
		}

		{
			// Insert the entry and exit blocks for the ssa.
			let block = self.phiplacer.add_block(BBInfo { addr: 0 });
			self.phiplacer.ssa.mark_start_node(&block);
			let zero = self.phiplacer.ssa.add_const(block, 0);
			self.phiplacer.write_variable(block, 0, zero); // cur = 0
			self.phiplacer.write_variable(block, 1, zero); // old = 0

			for (i, name) in self.regfile.whole_names.iter().enumerate() {
				let argnode = self.phiplacer.ssa.add_comment(block, name.clone());
				self.phiplacer.write_variable(block, i+1, argnode);
			}

			blocks[cfg.entry.index()] = block;

			let block = self.phiplacer.add_dynamic();
			self.phiplacer.ssa.mark_exit_node(&block);
			blocks[cfg.exit.index()] = block;
		}

		for (addr, i) in bb_iter {
			let block = self.phiplacer.add_block(BBInfo { addr: *addr });
			blocks[i.index()] = block;
			match cfg.g[*i] {
				CFGNodeData::Block(ref srcbb) => {
					self.process_block(block, srcbb);
				}
				_ => unreachable!(),
			}
		}

		for edge in cfg.g.raw_edges() {
			let i = match edge.weight.edge_type {
				CFGEdgeType::False => 0,
				CFGEdgeType::True => 1,
				CFGEdgeType::Unconditional => 2,
			};
			self.phiplacer.ssa.add_control_edge(
				blocks[edge.source().index()],
				blocks[edge.target().index()],
				i);
		}
		for &block in &blocks {
			self.phiplacer.seal_block(block);
		}
		//self.phiplacer.ssa.stable_indexing = false;
		//self.phiplacer.ssa.cleanup();

		{
			dce::collect(self.phiplacer.ssa);
		}
		//dce::collect(self.phiplacer.ssa, &[exit_regstate]);
		//self.phiplacer.ssa.cleanup();
	}

	fn process_in_flag(&mut self, block: T::ActionRef, _mval: &MVal) -> T::ValueRef {
		// this would be neccesary if parser didn't use EsilCur/EsilOld
		let _cur = self.phiplacer.read_variable(block, 0);
		let _old = self.phiplacer.read_variable(block, 1);
		//unimplemented!();
		self.phiplacer.ssa.invalid_value()
	}

	fn process_in(&mut self, block: T::ActionRef, mval: &MVal) -> T::ValueRef {
		match mval.val_type {
			MValType::Register  => self.regfile.read_register(&mut self.phiplacer, 2, block, &mval.name),
			MValType::Temporary => self.temps[&mval.name],
			MValType::Internal  => self.process_in_flag(block, mval),
			MValType::EsilCur   => self.phiplacer.read_variable(block, 0),
			MValType::EsilOld   => self.phiplacer.read_variable(block, 1),
			MValType::Unknown   => self.phiplacer.ssa.invalid_value(),
			                       //self.phiplacer.ssa.add_comment(block, &"Unknown".to_string()), // unimplemented!()
			MValType::Null      => self.phiplacer.ssa.invalid_value(),
		}
	}

	fn process_out(&mut self, block: T::ActionRef, mval: &MVal, value: T::ValueRef) {
		match mval.val_type {
			MValType::Register  => self.regfile.write_register(&mut self.phiplacer, 2, block, &mval.name, value),
			MValType::Temporary => {self.temps.insert(mval.name.clone(), value);},
			MValType::Null      => {},
			_                   => panic!(),
		}
	}

	fn process_op(&mut self, block: T::ActionRef, inst: &MInst, n0: T::ValueRef, n1: T::ValueRef) -> T::ValueRef {
		if inst.opcode == MOpcode::OpEq {
			return n0
		}

		let dsttype = match inst.dst.val_type {
			MValType::Null => ValueType::Integer{width: 0}, // there is no ValueType::None?
			_              => ValueType::Integer{width: inst.dst.size},
		};

		/*
		// TODO: When developing a ssa check pass, reuse this maybe
		let width = match inst.opcode {
		MOpcode::OpNarrow(w)
		| MOpcode::OpWiden(w) => { w },
		MOpcode::OpCmp => { 1 },
		_ => {
		let extract = |x: NodeData| -> Option<u8> {
		if let NodeData::Op(_, ValueType::Integer { width: w }) = x {
		Some(w)
		} else {
		None
		}
		};
		let w1 = self.phiplacer.ssa.safe_get_node_data(&n0)
		.map(&extract)
		.unwrap_or(None);

		let w2 = self.phiplacer.ssa.safe_get_node_data(&n1)
		.map(&extract)
		.unwrap_or(None);

		if w1 == None && w2 == None {
		// TODO: Replace by default value.
		64
		} else if w1 == None {
		w2.unwrap()
		} else if w2 == None {
		w1.unwrap()
		} else {
		let w1 = w1.unwrap();
		let w2 = w2.unwrap();
		// Check the width of the two operands.
		assert!(w1 == w2);
		w1
		}
		},
		};*/

		let nn = {
			let ref mut ssa = self.phiplacer.ssa;
			let nn = ssa.add_op(block, inst.opcode, dsttype);
			ssa.op_use(nn, 0, n0);
			ssa.op_use(nn, 1, n1);
			nn
		};

		if inst.update_flags {
			let old = self.phiplacer.read_variable(block, 0);
			self.phiplacer.write_variable(block, 1, old);
			self.phiplacer.write_variable(block, 0, nn);
		}

		return nn
	}

	fn process_block(&mut self, block: T::ActionRef, source: &BasicBlock) {
		let mut machinestate = self.phiplacer.ssa.to_value(block);
		for ref instruction in &source.instructions {
			let n0 = self.process_in(block, &instruction.operand_1);
			let n1 = self.process_in(block, &instruction.operand_2);

			if instruction.opcode == MOpcode::OpJmp {
				// TODO: In case of static jumps, this is trivial and does not need a selector.
				// In case of dynamic jump, the jump targets have to be determined.
				//self.ssa.g.add_edge(block, n0, SSAEdgeData::DynamicControl(0));
				break;
			}

			if instruction.opcode == MOpcode::OpCJmp {
				println!("Identified a selector: {:?} for block {:?}", n0, block);
				self.phiplacer.ssa.mark_selector(n0, block);
				continue;
			}

			let nn = self.process_op(block, instruction, n0, n1);

			if instruction.opcode == MOpcode::OpLoad {
				self.phiplacer.ssa.op_use(nn, 3, machinestate);
			}
			if instruction.opcode == MOpcode::OpStore {
				self.phiplacer.ssa.op_use(nn, 3, machinestate);
				machinestate = nn;
			}

			self.process_out(block, &instruction.dst, nn);
		}
	}
}
<commit_msg>Doc update [ci skip]<commit_after>//! Converts the from ESIL/CFG representation to SSA.

use std::collections::HashMap;
use petgraph::graph::NodeIndex;
use frontend::structs::LRegInfo;
use middle::cfg::NodeData as CFGNodeData;
use middle::cfg::EdgeType as CFGEdgeType;
use middle::cfg::{CFG, BasicBlock};
use middle::ssa::{BBInfo, SSA, SSAMod, ValueType};
use middle::ir::{MVal, MInst, MOpcode, MValType};
use middle::phiplacement::PhiPlacer;
use middle::regfile::SubRegisterFile;
use middle::dce;

pub type VarId = usize;

pub struct SSAConstruction<'a, T>
where T: Clone + SSAMod<BBInfo=BBInfo> + 'a {
	pub phiplacer: PhiPlacer<'a, T>,
	pub regfile:   SubRegisterFile,
	pub temps:     HashMap<String, T::ValueRef>,
}

impl<'a, T> SSAConstruction<'a, T>
where T: 'a + Clone +
SSAMod<BBInfo=BBInfo, ValueRef=NodeIndex, ActionRef=NodeIndex> {
	pub fn new(ssa: &'a mut T, reg_info: &LRegInfo) -> SSAConstruction<'a, T> {
		let mut sc = SSAConstruction {
			phiplacer: PhiPlacer::new(ssa),
			regfile:   SubRegisterFile::new(reg_info),
			temps:     HashMap::new(),
		};
		sc.phiplacer.add_variables(vec![
								   ValueType::Integer{width: 64}, // cur
								   ValueType::Integer{width: 64}  // old
		]);
		// make the following a method of regfile?
		sc.phiplacer.add_variables(sc.regfile.whole_registers.clone());
		sc
	}

	pub fn run(&mut self, cfg: &CFG) {
		let mut blocks = Vec::<T::ActionRef>::with_capacity(cfg.g.node_count());
		let bb_iter = cfg.bbs.iter();

		for _ in 0..cfg.g.node_count() {
			blocks.push(self.phiplacer.ssa.invalid_action());
		}

		{
			// Insert the entry and exit blocks for the ssa.
			let block = self.phiplacer.add_block(BBInfo { addr: 0 });
			self.phiplacer.ssa.mark_start_node(&block);
			let zero = self.phiplacer.ssa.add_const(block, 0);
			self.phiplacer.write_variable(block, 0, zero); // cur = 0
			self.phiplacer.write_variable(block, 1, zero); // old = 0

			for (i, name) in self.regfile.whole_names.iter().enumerate() {
				let argnode = self.phiplacer.ssa.add_comment(block, name.clone());
				self.phiplacer.write_variable(block, i+1, argnode);
			}

			blocks[cfg.entry.index()] = block;

			let block = self.phiplacer.add_dynamic();
			self.phiplacer.ssa.mark_exit_node(&block);
			blocks[cfg.exit.index()] = block;
		}

		for (addr, i) in bb_iter {
			let block = self.phiplacer.add_block(BBInfo { addr: *addr });
			blocks[i.index()] = block;
			match cfg.g[*i] {
				CFGNodeData::Block(ref srcbb) => {
					self.process_block(block, srcbb);
				}
				_ => unreachable!(),
			}
		}

		for edge in cfg.g.raw_edges() {
			let i = match edge.weight.edge_type {
				CFGEdgeType::False => 0,
				CFGEdgeType::True => 1,
				CFGEdgeType::Unconditional => 2,
			};
			self.phiplacer.ssa.add_control_edge(
				blocks[edge.source().index()],
				blocks[edge.target().index()],
				i);
		}
		for &block in &blocks {
			self.phiplacer.seal_block(block);
		}
		//self.phiplacer.ssa.stable_indexing = false;
		//self.phiplacer.ssa.cleanup();

		{
			dce::collect(self.phiplacer.ssa);
		}
		//dce::collect(self.phiplacer.ssa, &[exit_regstate]);
		//self.phiplacer.ssa.cleanup();
	}

	fn process_in_flag(&mut self, block: T::ActionRef, _mval: &MVal) -> T::ValueRef {
		// this would be neccesary if parser didn't use EsilCur/EsilOld
		let _cur = self.phiplacer.read_variable(block, 0);
		let _old = self.phiplacer.read_variable(block, 1);
		//unimplemented!();
		self.phiplacer.ssa.invalid_value()
	}

	fn process_in(&mut self, block: T::ActionRef, mval: &MVal) -> T::ValueRef {
		match mval.val_type {
			MValType::Register  => self.regfile.read_register(&mut self.phiplacer, 2, block, &mval.name),
			MValType::Temporary => self.temps[&mval.name],
			MValType::Internal  => self.process_in_flag(block, mval),
			MValType::EsilCur   => self.phiplacer.read_variable(block, 0),
			MValType::EsilOld   => self.phiplacer.read_variable(block, 1),
			MValType::Unknown   => self.phiplacer.ssa.invalid_value(),
			                       //self.phiplacer.ssa.add_comment(block, &"Unknown".to_string()), // unimplemented!()
			MValType::Null      => self.phiplacer.ssa.invalid_value(),
		}
	}

	fn process_out(&mut self, block: T::ActionRef, mval: &MVal, value: T::ValueRef) {
		match mval.val_type {
			MValType::Register  => self.regfile.write_register(&mut self.phiplacer, 2, block, &mval.name, value),
			MValType::Temporary => {self.temps.insert(mval.name.clone(), value);},
			MValType::Null      => {},
			_                   => panic!(),
		}
	}

	fn process_op(&mut self, block: T::ActionRef, inst: &MInst, n0: T::ValueRef, n1: T::ValueRef) -> T::ValueRef {
		if inst.opcode == MOpcode::OpEq {
			return n0
		}

		let dsttype = match inst.dst.val_type {
			MValType::Null => ValueType::Integer{width: 0}, // there is no ValueType::None?
			_              => ValueType::Integer{width: inst.dst.size},
		};

		let nn = {
			let ref mut ssa = self.phiplacer.ssa;
			let nn = ssa.add_op(block, inst.opcode, dsttype);
			ssa.op_use(nn, 0, n0);
			ssa.op_use(nn, 1, n1);
			nn
		};

		if inst.update_flags {
			let old = self.phiplacer.read_variable(block, 0);
			self.phiplacer.write_variable(block, 1, old);
			self.phiplacer.write_variable(block, 0, nn);
		}

		return nn
	}

	fn process_block(&mut self, block: T::ActionRef, source: &BasicBlock) {
		let mut machinestate = self.phiplacer.ssa.to_value(block);
		for ref instruction in &source.instructions {
			let n0 = self.process_in(block, &instruction.operand_1);
			let n1 = self.process_in(block, &instruction.operand_2);

			if instruction.opcode == MOpcode::OpJmp {
				// TODO: In case of static jumps, this is trivial and does not need a selector.
				// In case of dynamic jump, the jump targets have to be determined.
				//self.ssa.g.add_edge(block, n0, SSAEdgeData::DynamicControl(0));
				break;
			}

			if instruction.opcode == MOpcode::OpCJmp {
				println!("Identified a selector: {:?} for block {:?}", n0, block);
				self.phiplacer.ssa.mark_selector(n0, block);
				continue;
			}

			let nn = self.process_op(block, instruction, n0, n1);

			if instruction.opcode == MOpcode::OpLoad {
				self.phiplacer.ssa.op_use(nn, 3, machinestate);
			}
			if instruction.opcode == MOpcode::OpStore {
				self.phiplacer.ssa.op_use(nn, 3, machinestate);
				machinestate = nn;
			}

			self.process_out(block, &instruction.dst, nn);
		}
	}
}
<|endoftext|>