<commit_before>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc::SendError;

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use mioco;
use mioco::sync::mpsc::{Sender, channel};

use test_util::Tattle;

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// Represents the network state and provides various utilities acting upon it.
#[allow(missing_debug_implementations)]
pub struct NetHandle(Sender<()>);

impl NetHandle {
    /// Construct a new instance, starting a new coroutine and opening all network traffic on the spesified port.
    pub fn new() -> Self {
        NetHandle::new_tattle(None, None)
    }

    /// Constructs, with several optional structs that use global state for easier unit testing.
    pub fn new_tattle(tattle_closure_start: Option<Tattle>,
                      tattle_shutdown: Option<Tattle>)
                      -> Self {
        let (tx, rx) = channel::<()>(); // TODO: Maybe have more possible messages than () to shutdown?
        mioco::spawn(move || {
            if let Some(tattle) = tattle_closure_start {
                tattle.call();
            }
            loop {
                select!(
                    rx:r => {
                        if let Some(tattle) = tattle_shutdown {
                            tattle.call();
                        }
                        debug!("Shutting down coroutine");
                        let _ = rx.recv();
                        break;
                    },
                );
            }
        });
        NetHandle(tx)
    }

    /// Shuts down the socket/listener, closing all connections.
    pub fn shutdown(&self) -> Result<(), SendError<()>> {
        self.0.send(())
    }
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("Because localhost can resolve to both 127.0.0.1, and the vairous IPV6 versions \
                of 127.0.0.1, it may not be used. Please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("The given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

#[allow(unused)]    // TODO: Remove allow(unused).
fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
#[allow(unused)]
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<commit_msg>Makes the net coroutine's channel use a enum for various actions, instead of a () for shutdown<commit_after>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc::SendError;

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use mioco;
use mioco::sync::mpsc::{Sender, channel};

use test_util::Tattle;

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// Represents the network state and provides various utilities acting upon it.
#[allow(missing_debug_implementations)]
pub struct NetHandle(Sender<NetAction>);

impl NetHandle {
    /// Construct a new instance, starting a new coroutine and opening all network traffic on the spesified port.
    pub fn new() -> Self {
        NetHandle::new_tattle(None, None)
    }

    /// Constructs, with several optional structs that use global state for easier unit testing.
    pub fn new_tattle(tattle_closure_start: Option<Tattle>,
                      tattle_shutdown: Option<Tattle>)
                      -> Self {
        let (tx, rx) = channel::<NetAction>();
        mioco::spawn(move || {
            if let Some(tattle) = tattle_closure_start {
                tattle.call();
            }
            loop {
                select!(
                    rx:r => {
                        use net::NetAction::*;
                        match rx.recv().expect("Channel to net coroutine improperly closed") {
                            Shutdown => {
                                if let Some(tattle) = tattle_shutdown {
                                    tattle.call();
                                }
                                debug!("Shutting down coroutine");
                                break;
                            }
                        }
                    },
                );
            }
        });
        NetHandle(tx)
    }

    /// Shuts down the socket/listener, closing all connections.
    pub fn shutdown(&self) -> Result<(), SendError<NetAction>> {
        self.0.send(NetAction::Shutdown)
    }
}

/// Represents all the possible actions inside a network coroutine.
///
/// Maps mostly 1:1 with the interface of NetHandle.
#[derive(Clone, Copy, Debug)]
pub enum NetAction {
    /// Kill the coroutine, and any open connections.
    Shutdown,
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("Because localhost can resolve to both 127.0.0.1, and the vairous IPV6 versions \
                of 127.0.0.1, it may not be used. Please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("The given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

#[allow(unused)]    // TODO: Remove allow(unused).
fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
#[allow(unused)]
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<|endoftext|>


<commit_before>
use std::collections::HashSet;
use std::process::Command;

/// Find dependencies for the given exe/dll
///
/// ignore is a list of dll names that should not
/// be added to deps.
///
/// Returns (format, deps) format is the binary format
/// (e.g. pei-x86-64) deps is a set of dependency dlls.
///
/// Internally this calls objdump -p <file>
///
pub fn deps(file: &str, ignore: &[&str]) -> Result<(String,HashSet<String>),String> {

    let command = Command::new("objdump")
        .arg("-p")
        .arg(file)
        .output().unwrap_or_else(|e| {panic!("Failed to execute objdump: {}", e)});

    if !command.status.success() {
        return Err(format!("Error executing objdump({}): {}",
                 command.status.code().unwrap_or(-1),
                 String::from_utf8_lossy(&command.stderr)));
    }

    let mut deps = HashSet::new();
    let out = String::from_utf8_lossy(&command.stdout);
    let mut format = String::new();

    for line in out.lines() {
        if line.starts_with("\tDLL Name:") {
            if let Some(dll) = line.split(": ").nth(1) {
                if !ignore.contains(&dll.to_lowercase().as_ref()) {
                    deps.insert(String::from(dll));
                }
            }
        } else if line.contains(file) {
            format = line.split(':')
                .nth(1).unwrap_or("").trim()
                .split_whitespace().last().unwrap_or("").to_owned();
        }
    }

    Ok((format,deps))
}

<commit_msg>Windows: Trim objdump line output to avoid \r newline<commit_after>
use std::collections::HashSet;
use std::process::Command;

/// Find dependencies for the given exe/dll
///
/// ignore is a list of dll names that should not
/// be added to deps.
///
/// Returns (format, deps) format is the binary format
/// (e.g. pei-x86-64) deps is a set of dependency dlls.
///
/// Internally this calls objdump -p <file>
///
pub fn deps(file: &str, ignore: &[&str]) -> Result<(String,HashSet<String>),String> {

    let command = Command::new("objdump")
        .arg("-p")
        .arg(file)
        .output().unwrap_or_else(|e| {panic!("Failed to execute objdump: {}", e)});

    if !command.status.success() {
        return Err(format!("Error executing objdump({}): {}",
                 command.status.code().unwrap_or(-1),
                 String::from_utf8_lossy(&command.stderr)));
    }

    let mut deps = HashSet::new();
    let out = String::from_utf8_lossy(&command.stdout);
    let mut format = String::new();

    for line in out.lines() {
        let xline = line.trim();
        if xline.starts_with("DLL Name:") {
            if let Some(dll) = xline.split(": ").nth(1) {
                if !ignore.contains(&dll.to_lowercase().as_ref()) {
                    deps.insert(String::from(dll));
                }
            }
        } else if xline.contains(file) {
            format = xline.split(':')
                .nth(1).unwrap_or("").trim()
                .split_whitespace().last().unwrap_or("").to_owned();
        }
    }

    Ok((format,deps))
}

<|endoftext|>


<commit_before>use luminance::blending::{Equation, Factor};
use luminance::pipeline::Pipeline;
use luminance::tess::{Mode, Tess, TessRender, TessVertices};
use luminance::texture::{Dim2, Flat, Unit};
use luminance::vertex::{Vertex, VertexFormat};
use std::cell::RefCell;

use compositing::{ColorMap, DepthMap};
use framebuffer::Framebuffer2D;
use resource::{Res, ResCache};
use shader::{Program, Uniform};
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  pub center: Vert,
  pub radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, cache: &mut ResCache) -> Self {
    let tri_program = cache.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = cache.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = cache.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tris = tris_ref.as_slice_mut().unwrap();
    let mut tri_i = 0;

    let mut discs_ref = self.discs.borrow_mut();
    let mut discs = discs_ref.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, c, b, d];

      for &v in &abcd {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    (tri_i, disc_i)
  }

  pub fn render(&self, framebuffer: &Framebuffer2D<ColorMap, DepthMap>, input: &RenderInput) {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    Pipeline::new(framebuffer, [0., 0., 0., 0.], &[], &[]).enter(|shd_gate| {
      shd_gate.new(&tri_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, true, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(tris, &[], &[], &[]);
        });
      });

      let disc_uniforms = [DISC_SCREEN_RATIO.alter(self.ratio)];
      shd_gate.new(&disc_program, &disc_uniforms, &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, true, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(discs, &[], &[], &[]);
        });
      });

      if let Some((texts, text_scale)) = input.texts {
        shd_gate.new(&text_program, &[], &[], &[]).enter(|rdr_gate| {
          for text in texts {
            let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
            let (tex_w, tex_h) = text.text_texture.size();
            let uniforms = [
              TEXT_SAMPLER.alter(Unit::new(0)),
              TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
              TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
              TEXT_SCALE.alter(text_scale),
              TEXT_COLOR.alter(text.left_lower.color),
            ];

            rdr_gate.new(blending, true, &uniforms, &[&***text.text_texture], &[]).enter(|tess_gate| {
              tess_gate.render(text_quad.clone(), &[], &[], &[]);
            });
          }
        });
      }
    });
  }
}

#[derive(Clone)]
pub struct RenderInput<'a> {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'a>], f32)>
}

impl<'a> RenderInput<'a> {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'a>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<commit_msg>This should have fixed the panic errors from tess mapping.<commit_after>use luminance::blending::{Equation, Factor};
use luminance::pipeline::Pipeline;
use luminance::tess::{Mode, Tess, TessRender, TessVertices};
use luminance::texture::{Dim2, Flat, Unit};
use luminance::vertex::{Vertex, VertexFormat};
use std::cell::RefCell;

use compositing::{ColorMap, DepthMap};
use framebuffer::Framebuffer2D;
use resource::{Res, ResCache};
use shader::{Program, Uniform};
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  pub center: Vert,
  pub radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, cache: &mut ResCache) -> Self {
    let tri_program = cache.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = cache.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = cache.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tri_i = 0;
    if let Ok(mut tris) = tris_ref.as_slice_mut() {
      for &Triangle(a, b, c) in input.triangles {
        let abc = [a, b, c];

        for &v in &abc {
          tris[tri_i] = v.to_clip_space(&self.unit_converter);
          tri_i += 1;
        }
      }

      for &Quad(a, b, c, d) in input.quads {
        let abcd = [a, b, c, c, b, d];

        for &v in &abcd {
          tris[tri_i] = v.to_clip_space(&self.unit_converter);
          tri_i += 1;
        }
      }
    }

    let mut discs_ref = self.discs.borrow_mut();
    let mut disc_i = 0;
    if let Ok(mut discs) = discs_ref.as_slice_mut() {
      for disc in input.discs {
        discs[disc_i] = disc.to_clip_space(&self.unit_converter);
        disc_i += 1;
      }
    }

    (tri_i, disc_i)
  }

  pub fn render(&self, framebuffer: &Framebuffer2D<ColorMap, DepthMap>, input: &RenderInput) {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    Pipeline::new(framebuffer, [0., 0., 0., 0.], &[], &[]).enter(|shd_gate| {
      shd_gate.new(&tri_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, true, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(tris, &[], &[], &[]);
        });
      });

      let disc_uniforms = [DISC_SCREEN_RATIO.alter(self.ratio)];
      shd_gate.new(&disc_program, &disc_uniforms, &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, true, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(discs, &[], &[], &[]);
        });
      });

      if let Some((texts, text_scale)) = input.texts {
        shd_gate.new(&text_program, &[], &[], &[]).enter(|rdr_gate| {
          for text in texts {
            let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
            let (tex_w, tex_h) = text.text_texture.size();
            let uniforms = [
              TEXT_SAMPLER.alter(Unit::new(0)),
              TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
              TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
              TEXT_SCALE.alter(text_scale),
              TEXT_COLOR.alter(text.left_lower.color),
            ];

            rdr_gate.new(blending, true, &uniforms, &[&***text.text_texture], &[]).enter(|tess_gate| {
              tess_gate.render(text_quad.clone(), &[], &[], &[]);
            });
          }
        });
      }
    });
  }
}

#[derive(Clone)]
pub struct RenderInput<'a> {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'a>], f32)>
}

impl<'a> RenderInput<'a> {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'a>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {
                let patch = Program::attempt_forward_jump(
                    &self.instructions,
                    index,
                    goal,
                    self.current_depth,
                );
                println!("SEEKING BRANCH\n{:?}\n", patch);
                return self.update(patch).execute(vm);
            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            if vm.cells[vm.data_pointer] == 0 {
                                self.current_depth -= 1;
                                continue;
                            }

                            let patch = Program::backward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                            );
                            println!("BACKWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        Command::JumpForward => {
                            if vm.cells[vm.data_pointer] != 0 {
                                self.current_depth += 1;
                                continue;
                            }

                            let patch = Program::attempt_forward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                                self.current_depth,
                            );
                            println!("FORWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        command if start < self.instructions.len() => vm.apply(command),

                        _ => {}
                    }
                }
            }

            _ => {}
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(commands, Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![Command::JumpForward, Command::JumpForward, Command::JumpBackward];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(actual, ProgramPatch {
            instruction_pointer: 3,
            current_depth: 1,
            status: ProgramStatus::Seeking(0),
        })
    }
}
<commit_msg>Fix invocation of find_by not using subslicing<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {
                let patch = Program::attempt_forward_jump(
                    &self.instructions,
                    index,
                    goal,
                    self.current_depth,
                );
                println!("SEEKING BRANCH\n{:?}\n", patch);
                return self.update(patch).execute(vm);
            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            if vm.cells[vm.data_pointer] == 0 {
                                self.current_depth -= 1;
                                continue;
                            }

                            let patch = Program::backward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                            );
                            println!("BACKWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        Command::JumpForward => {
                            if vm.cells[vm.data_pointer] != 0 {
                                self.current_depth += 1;
                                continue;
                            }

                            let patch = Program::attempt_forward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                                self.current_depth,
                            );
                            println!("FORWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        command if start < self.instructions.len() => vm.apply(command),

                        _ => {}
                    }
                }
            }

            _ => {}
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(&commands[index..], Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![Command::JumpForward, Command::JumpForward, Command::JumpBackward];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(actual, ProgramPatch {
            instruction_pointer: 3,
            current_depth: 1,
            status: ProgramStatus::Seeking(0),
        })
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str::ToStr;
use std::vec;

#[deriving(Eq)]
pub struct NumericValue {
    representation: ~str,
    value: f64,
    int_value: Option<i64>,
}

#[deriving(Eq)]
pub struct SourceLocation {
    line: uint,  // First line is 1
    column: uint,  // First character of a line is at column 1
}

pub type Node = (ComponentValue, SourceLocation);  // TODO this is not a good name

#[deriving(Eq)]
pub enum ComponentValue {
    // Preserved tokens.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    IDHash(~str),  // Hash that is a valid ID selector.
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue),
    Percentage(NumericValue),
    Dimension(NumericValue, ~str),
    UnicodeRange(char, char), // UnicodeRange {start: char, end: char},
    EmptyUnicodeRange,
    WhiteSpace,
    Colon,  // :
    Semicolon,  // ;
    Comma,  // ,
    IncludeMath, // ~=
    DashMatch, // |=
    PrefixMatch, // ^=
    SuffixMatch, // $=
    SubstringMatch, // *=
    Column, // ||
    CDO,  // <!--
    CDC,  // -->

    // Function
    Function(~str, ~[ComponentValue]),  // name, arguments

    // Simple block
    ParenthesisBlock(~[ComponentValue]),  // (…)
    SquareBracketBlock(~[ComponentValue]),  // […]
    CurlyBracketBlock(~[Node]),  // {…}

    // These are always invalid
    BadURL,
    BadString,
    CloseParenthesis, // )
    CloseSquareBracket, // ]
    CloseCurlyBracket, // }
}

#[deriving(Eq)]
pub struct Declaration {
    location: SourceLocation,
    name: ~str,
    value: ~[ComponentValue],
    important: bool,
}

#[deriving(Eq)]
pub struct QualifiedRule {
    location: SourceLocation,
    prelude: ~[ComponentValue],
    block: ~[Node],
}

#[deriving(Eq)]
pub struct AtRule {
    location: SourceLocation,
    name: ~str,
    prelude: ~[ComponentValue],
    block: Option<~[Node]>,
}

#[deriving(Eq)]
pub enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

#[deriving(Eq)]
pub enum Rule {
    QualifiedRule(QualifiedRule),
    AtRule(AtRule),
}

#[deriving(Eq)]
pub struct SyntaxError {
    location: SourceLocation,
    reason: ErrorReason,
}

#[deriving(Eq)]
pub enum ErrorReason {
    ErrEmptyInput,  // Parsing a single "thing", found only whitespace.
    ErrExtraInput,  // Found more non-whitespace after parsing a single "thing".
    ErrMissingQualifiedRuleBlock,  // EOF in a qualified rule prelude, before '{'
    ErrInvalidDeclarationSyntax,
    ErrInvalidBangImportantSyntax,
    // This is meant to be extended
}

impl ToStr for SyntaxError {
    fn to_str(&self) -> ~str {
        fmt!("%u:%u %?", self.location.line, self.location.column, self.reason)
    }
}

pub trait SkipWhitespaceIterable<'self> {
    pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self>;
}

impl<'self> SkipWhitespaceIterable<'self> for &'self [ComponentValue] {
    pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self> {
        SkipWhitespaceIterator{ iter: self.iter() }
    }
}

struct SkipWhitespaceIterator<'self> {
    iter: vec::VecIterator<'self, ComponentValue>,
}

impl<'self> Iterator<&'self ComponentValue> for SkipWhitespaceIterator<'self> {
    fn next(&mut self) -> Option<&'self ComponentValue> {
        for component_value in self.iter {
            if component_value != &WhiteSpace { return Some(component_value) }
        }
        None
    }
}
<commit_msg>Add ~[ComponentValue].consume_skip_whitespace()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str::ToStr;
use std::vec;

#[deriving(Eq)]
pub struct NumericValue {
    representation: ~str,
    value: f64,
    int_value: Option<i64>,
}

#[deriving(Eq)]
pub struct SourceLocation {
    line: uint,  // First line is 1
    column: uint,  // First character of a line is at column 1
}

pub type Node = (ComponentValue, SourceLocation);  // TODO this is not a good name

#[deriving(Eq)]
pub enum ComponentValue {
    // Preserved tokens.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    IDHash(~str),  // Hash that is a valid ID selector.
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue),
    Percentage(NumericValue),
    Dimension(NumericValue, ~str),
    UnicodeRange(char, char), // UnicodeRange {start: char, end: char},
    EmptyUnicodeRange,
    WhiteSpace,
    Colon,  // :
    Semicolon,  // ;
    Comma,  // ,
    IncludeMath, // ~=
    DashMatch, // |=
    PrefixMatch, // ^=
    SuffixMatch, // $=
    SubstringMatch, // *=
    Column, // ||
    CDO,  // <!--
    CDC,  // -->

    // Function
    Function(~str, ~[ComponentValue]),  // name, arguments

    // Simple block
    ParenthesisBlock(~[ComponentValue]),  // (…)
    SquareBracketBlock(~[ComponentValue]),  // […]
    CurlyBracketBlock(~[Node]),  // {…}

    // These are always invalid
    BadURL,
    BadString,
    CloseParenthesis, // )
    CloseSquareBracket, // ]
    CloseCurlyBracket, // }
}

#[deriving(Eq)]
pub struct Declaration {
    location: SourceLocation,
    name: ~str,
    value: ~[ComponentValue],
    important: bool,
}

#[deriving(Eq)]
pub struct QualifiedRule {
    location: SourceLocation,
    prelude: ~[ComponentValue],
    block: ~[Node],
}

#[deriving(Eq)]
pub struct AtRule {
    location: SourceLocation,
    name: ~str,
    prelude: ~[ComponentValue],
    block: Option<~[Node]>,
}

#[deriving(Eq)]
pub enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

#[deriving(Eq)]
pub enum Rule {
    QualifiedRule(QualifiedRule),
    AtRule(AtRule),
}

#[deriving(Eq)]
pub struct SyntaxError {
    location: SourceLocation,
    reason: ErrorReason,
}

#[deriving(Eq)]
pub enum ErrorReason {
    ErrEmptyInput,  // Parsing a single "thing", found only whitespace.
    ErrExtraInput,  // Found more non-whitespace after parsing a single "thing".
    ErrMissingQualifiedRuleBlock,  // EOF in a qualified rule prelude, before '{'
    ErrInvalidDeclarationSyntax,
    ErrInvalidBangImportantSyntax,
    // This is meant to be extended
}

impl ToStr for SyntaxError {
    fn to_str(&self) -> ~str {
        fmt!("%u:%u %?", self.location.line, self.location.column, self.reason)
    }
}

pub trait SkipWhitespaceIterable<'self> {
    pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self>;
}

impl<'self> SkipWhitespaceIterable<'self> for &'self [ComponentValue] {
    pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self> {
        SkipWhitespaceIterator{ iter: self.iter() }
    }
}

struct SkipWhitespaceIterator<'self> {
    iter: vec::VecIterator<'self, ComponentValue>,
}

impl<'self> Iterator<&'self ComponentValue> for SkipWhitespaceIterator<'self> {
    fn next(&mut self) -> Option<&'self ComponentValue> {
        for component_value in self.iter {
            if component_value != &WhiteSpace { return Some(component_value) }
        }
        None
    }
}

pub trait ConsumeSkipWhitespaceIterable {
    pub fn consume_skip_whitespace(self) -> ConsumeSkipWhitespaceIterator;
}

impl ConsumeSkipWhitespaceIterable for ~[ComponentValue] {
    pub fn consume_skip_whitespace(self) -> ConsumeSkipWhitespaceIterator {
        ConsumeSkipWhitespaceIterator{ iter: self.consume_iter() }
    }
}

struct ConsumeSkipWhitespaceIterator {
    iter: vec::ConsumeIterator<ComponentValue>,
}

impl Iterator<ComponentValue> for ConsumeSkipWhitespaceIterator {
    fn next(&mut self) -> Option<ComponentValue> {
        for component_value in self.iter {
            if component_value != WhiteSpace { return Some(component_value) }
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Enviroment data

use alloc::boxed::Box;

use fs::File;
use path::PathBuf;
use io::Result;
use slice::Iter;
use string::ToString;
use vec::Vec;

use syscall::{SysError, sys_chdir, ENOENT};

static mut _args: *mut Vec<&'static str> = 0 as *mut Vec<&'static str>;

/// Arguments
pub fn args<'a>() -> Iter<'a, &'static str> {
    unsafe { (*_args).iter() }
}

/// Initialize arguments
pub unsafe fn args_init(args: Vec<&'static str>) {
    _args = Box::into_raw(box args);
}

/// Destroy arguments
pub unsafe fn args_destroy() {
    if _args as usize > 0 {
        drop(Box::from_raw(_args));
    }
}

/// Method to return the current directory
/// If the current directory cannot be found, None will be returned
pub fn current_dir() -> Result<PathBuf> {
    // Return the current path
    match File::open("./") {
        Ok(file) => {
            match file.path() {
                Ok(path) => Ok(path),
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

/// Set the current directory
pub fn set_current_dir(path: &str) -> Result<()> {
    let file_result = if path.is_empty() || path.ends_with('/') {
        File::open(path)
    } else {
        File::open(&(path.to_string() + "/"))
    };

    match file_result {
        Ok(file) => {
            match file.path() {
                Ok(path) => {
                    if let Some(path_str) = path.to_str() {
                        let path_c = path_str.to_string() + "\0";
                        match SysError::demux(unsafe { sys_chdir(path_c.as_ptr()) }) {
                            Ok(_) => Ok(()),
                            Err(err) => Err(err),
                        }
                    } else {
                        Err(SysError::new(ENOENT))
                    }
                }
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}
<commit_msg>Add `env::var()` as filler to reduce error messages<commit_after>//! Enviroment data

use alloc::boxed::Box;

use fs::File;
use path::PathBuf;
use io::Result;
use slice::Iter;
use string::{String, ToString};
use vec::Vec;

use syscall::{SysError, sys_chdir, ENOENT};

static mut _args: *mut Vec<&'static str> = 0 as *mut Vec<&'static str>;

/// Arguments
pub fn args<'a>() -> Iter<'a, &'static str> {
    unsafe { (*_args).iter() }
}

/// Initialize arguments
pub unsafe fn args_init(args: Vec<&'static str>) {
    _args = Box::into_raw(box args);
}

/// Destroy arguments
pub unsafe fn args_destroy() {
    if _args as usize > 0 {
        drop(Box::from_raw(_args));
    }
}

/// Method to return the current directory
/// If the current directory cannot be found, None will be returned
pub fn current_dir() -> Result<PathBuf> {
    // Return the current path
    match File::open("./") {
        Ok(file) => {
            match file.path() {
                Ok(path) => Ok(path),
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

/// Set the current directory
pub fn set_current_dir(path: &str) -> Result<()> {
    let file_result = if path.is_empty() || path.ends_with('/') {
        File::open(path)
    } else {
        File::open(&(path.to_string() + "/"))
    };

    match file_result {
        Ok(file) => {
            match file.path() {
                Ok(path) => {
                    if let Some(path_str) = path.to_str() {
                        let path_c = path_str.to_string() + "\0";
                        match SysError::demux(unsafe { sys_chdir(path_c.as_ptr()) }) {
                            Ok(_) => Ok(()),
                            Err(err) => Err(err),
                        }
                    } else {
                        Err(SysError::new(ENOENT))
                    }
                }
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

// TODO: Fully implement `env::var()`
pub fn var(key: &str) -> Result<String> {
    Ok("This is code filler".to_string())
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: Ord+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                symbol_a.cmp(symbol_b)
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges
        // You can call Ndfa.fix_overlapping_ranges() to remove any overlapping ranges from an NDFA

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        // Read back 'abc' manually
        let mut state = state_machine.start();
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_build_dfa_with_overlapping_range() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = (MatchRange('a', 'c').append("a")).or(MatchRange('b', 'd').append("b")).to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        println!("{:?}", state_machine);

        // Read back 'ba' manually
        let mut state = state_machine.start();
        let mut input = "ba".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }

        // Read back 'bb' manually
        state = state_machine.start();
        input = "bb".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<commit_msg>Improve documentation for the DFA compiler<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder. Usually the `SymbolRangeDfaBuilder` would be used but the
//! compiler can be used with any object implementing the `DfaBuilder` trait.
//!
//! The NDFA should not have any overlapping symbols, which is to say symbols that are not equal and yet could match the same
//! input symbol. If the builder finds that two NDFA states have identical output symbols, then the builder will pick the symbol
//! that compares as being lower as the final output symbol.
//!
//! Any NDFA can be converted into a DFA: if the NDFA can move to two states as the result of a particular input symbol, the DFA
//! just needs a single new state representing both those possible states. In this way, the NDFA can be converted into a form where
//! every input symbol only maps to a single transition.
//!
//! Normally the compiler isn't used directly: it's called by implementations of `PrepareToMatch`. It's useful for manually building
//! DFAs for other purposes or for creating new types of state machine that aren't already in this library.
//!
//! ```
//! let ndfa     = "abc".into_pattern().to_ndfa("Success");
//! let builder  = SymbolRangeDfaBuilder::new();
//!
//! let state_machine = DfaCompiler::build(ndfa, builder);
//! ```
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: Ord+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                symbol_a.cmp(symbol_b)
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges
        // You can call Ndfa.fix_overlapping_ranges() to remove any overlapping ranges from an NDFA

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        // Read back 'abc' manually
        let mut state = state_machine.start();
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_build_dfa_with_overlapping_range() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = (MatchRange('a', 'c').append("a")).or(MatchRange('b', 'd').append("b")).to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        println!("{:?}", state_machine);

        // Read back 'ba' manually
        let mut state = state_machine.start();
        let mut input = "ba".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }

        // Read back 'bb' manually
        state = state_machine.start();
        input = "bb".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 2);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>use self::streamql::statement;
pub use self::streamql::ParseError;
use super::row_builder::RowBuilder;
use super::schema::Type;
use super::value::Value;

mod integration_tests;

peg_file! streamql("streamql.rustpeg");

pub fn parse_statement(query: &str) -> Result<Statement, ParseError> {
    statement(query)
}

#[derive(Debug)]
pub enum Statement {
    // Stream & Keys
    Insert(String, RowBuilder),
    // name
    DeclareStream(String, Vec<ColumnSpec>),
    DropStream,
    UseDatabase,
    // Stream
    Select(String),
    Subscribe,
}

// infix operators
// used for 2 expressions
// 2 expressions must evaluate to a bool
enum Operator {
    Equal,
    NotEqual,
    GreaterThan,
    GreaterThanEqual,
    LessThan,
    LessThanEqual,
    And,
    Or
}

pub enum Expression {
    Value(Value),
    Comparison(Operator, Box<Expression>, Box<Expression>),
    Function(String, Vec<Expression> ),
    Field(String), // field name
    None,
}

#[derive(Debug)]
pub struct ColumnSpec {
    pub name: String,
    pub ftype: Type,
}

impl ColumnSpec {
    fn new(name: String, ftype: Type) -> ColumnSpec {
        ColumnSpec{name: name,
                   ftype: ftype}
    }
}

#[cfg(test)]
mod test {
    use super::parse_statement;
    use super::Statement;
    use super::streamql::*;
    use db::value::Value;

    #[test]
    fn test_basic_insert() {

        let result = parse_statement("INSERT INTO test set k=1;").unwrap();

        if let Statement::Insert(stream, builder) = result {
            assert_eq!(stream, String::from("test"));
        } else {
            panic!("")
        }
        let x = "INSERT INTO test set k=1, v=2;";
        let result = parse_statement(x).unwrap();

    }

    #[test]
    fn test_parsing_with_quoted_string() {
        let result = parse_statement("INSERT INTO test set k='test';").unwrap();
        let result = parse_statement("INSERT INTO test set k='test my ''friend''';").unwrap();

    }

    #[test]
    fn test_int_parsing() {
        let tmp = int_value("42").unwrap();
    }

    #[test]
    fn test_basic_string_parsing() {
        string("hello this is a test").unwrap();
    }

    #[test]
    fn test_escaped_string() {
        let x = string("hello this is a ''test''").unwrap();
        assert_eq!(x, "hello this is a 'test'");
    }

    #[test]
    fn test_quoted_string() {
        let x = "'it''s mine'";
        let p = quoted_string(x).unwrap();
        assert_eq!(p, "it's mine");
    }

    #[test]
    fn value_string_parsing() {
        let x = "'hello'";
        if Value::from(x) == value(x).unwrap() {
            assert_eq!(x, "hello");
        }

    }

    #[test]
    fn declare_stream_parsing() {
        let x = "declare stream readings ( ts int, val int, s text );";
        let p = parse_statement(x).unwrap();
    }

    #[test]
    fn test_basic_parse_column_specification() {
        let x = "ts int";
        let p = column_spec(x).unwrap();

        let x = "ts text";
        let p = column_spec(x).unwrap();
    }

    #[test]
    fn test_column_spec_list() {
        let x = "ts int, val int, s text ";
        let p = column_spec_list(x).unwrap();

        assert_eq!(p.len(), 3);

        assert_eq!(p[0].name, "ts");
        assert_eq!(p[1].name, "val");
        assert_eq!(p[2].name, "s");
    }

    #[test]
    fn test_select_queries() {
        let queries = ["select * from test",
                        "select name, age from users",
                        "select name from cities where state = 'CA'"];
        for q in queries.into_iter() {
            parse_statement(&q).expect(q);
        }

    }

    #[test]
    fn test_field_list() {
        let queries = ["name, email",
            "*", "stuff"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }
    }

    #[test]
    fn test_where_clause() {
        let queries = ["where name = 'jon'",
        "where id = 5",
        "where name = 'bill' and age > 35"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }

    }

    // expression testing
    #[test]
    fn test_value_expression() {
        let tmp = expression_value("1").expect("1");
    }
    #[test]
    fn test_field_expression() {
        let tmp = expression_field("name")
                   .expect("name didn't parse");
    }

    #[test]
    fn test_operators() {
        expression_operator("name > 5")
            .expect("Expecting name > 5");

        let x = "age > 10 and city = 'Boston'";
        // technically is this:
        // let x = "((age > 10) and (city = 'Boston'))";
        // need to rewrite as a bunch of nested binary ops
        // do i need a second parser just to rewrite?
        expression(x).expect(x);

        // same as above but needed to be safe
        let x = "(age > 10) and city = 'Boston'";
        expression(x).expect(x);
    }

    #[test]
    fn test_grouping() {
        expression_grouped("(fname > 0)")
            .expect("Expecting name > 5");
        expression("(fname > 0)")
            .expect("Expecting name > 5");

    }

    #[test]
    fn test_and() {
        //expression_and()
    }

}

<commit_msg>i think expressions are ok for a bit<commit_after>use self::streamql::statement;
pub use self::streamql::ParseError;
use super::row_builder::RowBuilder;
use super::schema::Type;
use super::value::Value;

mod integration_tests;

peg_file! streamql("streamql.rustpeg");

pub fn parse_statement(query: &str) -> Result<Statement, ParseError> {
    statement(query)
}

#[derive(Debug)]
pub enum Statement {
    // Stream & Keys
    Insert(String, RowBuilder),
    // name
    DeclareStream(String, Vec<ColumnSpec>),
    DropStream,
    UseDatabase,
    // Stream
    Select(String),
    Subscribe,
}

// infix operators
// used for 2 expressions
// 2 expressions must evaluate to a bool
#[derive(Debug, PartialEq)]
enum Operator {
    Equal,
    NotEqual,
    GreaterThan,
    GreaterThanEqual,
    LessThan,
    LessThanEqual,
    And,
    Or
}

#[derive(Debug)]
pub enum Expression {
    Value(Value),
    Comparison(Operator, Box<Expression>, Box<Expression>),
    Function(String, Vec<Expression> ),
    Field(String), // field name
    None,
}

#[derive(Debug)]
pub struct ColumnSpec {
    pub name: String,
    pub ftype: Type,
}

impl ColumnSpec {
    fn new(name: String, ftype: Type) -> ColumnSpec {
        ColumnSpec{name: name,
                   ftype: ftype}
    }
}

#[cfg(test)]
mod test {
    use super::parse_statement;
    use super::{Statement, Expression, Operator};
    use super::streamql::*;
    use db::value::Value;

    #[test]
    fn test_basic_insert() {

        let result = parse_statement("INSERT INTO test set k=1;").unwrap();

        if let Statement::Insert(stream, builder) = result {
            assert_eq!(stream, String::from("test"));
        } else {
            panic!("")
        }
        let x = "INSERT INTO test set k=1, v=2;";
        let result = parse_statement(x).unwrap();

    }

    #[test]
    fn test_parsing_with_quoted_string() {
        let result = parse_statement("INSERT INTO test set k='test';").unwrap();
        let result = parse_statement("INSERT INTO test set k='test my ''friend''';").unwrap();

    }

    #[test]
    fn test_int_parsing() {
        let tmp = int_value("42").unwrap();
    }

    #[test]
    fn test_basic_string_parsing() {
        string("hello this is a test").unwrap();
    }

    #[test]
    fn test_escaped_string() {
        let x = string("hello this is a ''test''").unwrap();
        assert_eq!(x, "hello this is a 'test'");
    }

    #[test]
    fn test_quoted_string() {
        let x = "'it''s mine'";
        let p = quoted_string(x).unwrap();
        assert_eq!(p, "it's mine");
    }

    #[test]
    fn value_string_parsing() {
        let x = "'hello'";
        if Value::from(x) == value(x).unwrap() {
            assert_eq!(x, "hello");
        }

    }

    #[test]
    fn declare_stream_parsing() {
        let x = "declare stream readings ( ts int, val int, s text );";
        let p = parse_statement(x).unwrap();
    }

    #[test]
    fn test_basic_parse_column_specification() {
        let x = "ts int";
        let p = column_spec(x).unwrap();

        let x = "ts text";
        let p = column_spec(x).unwrap();
    }

    #[test]
    fn test_column_spec_list() {
        let x = "ts int, val int, s text ";
        let p = column_spec_list(x).unwrap();

        assert_eq!(p.len(), 3);

        assert_eq!(p[0].name, "ts");
        assert_eq!(p[1].name, "val");
        assert_eq!(p[2].name, "s");
    }

    #[test]
    fn test_select_queries() {
        let queries = ["select * from test",
                        "select name, age from users",
                        "select name from cities where state = 'CA'"];
        for q in queries.into_iter() {
            parse_statement(&q).expect(q);
        }

    }

    #[test]
    fn test_field_list() {
        let queries = ["name, email",
            "*", "stuff"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }
    }

    #[test]
    fn test_where_clause() {
        let queries = ["where name = 'jon'",
        "where id = 5",
        "where name = 'bill' and age > 35"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }

    }

    // expression testing
    #[test]
    fn test_value_expression() {
        let tmp = expression_value("1").expect("1");
    }
    #[test]
    fn test_field_expression() {
        let tmp = expression_field("name")
                   .expect("name didn't parse");
    }

    #[test]
    fn test_operators() {
        expression_operator("name > 5")
            .expect("Expecting name > 5");

        let x = "age > 10 and city = 'Boston'";
        // technically is this:
        // let x = "((age > 10) and (city = 'Boston'))";
        // need to rewrite as a bunch of nested binary ops
        // do i need a second parser just to rewrite?
        expression(x).expect(x);

        // same as above but needed to be safe
        let x = "(age > 10) and city = 'Boston'";
        expression(x).expect(x);

        let x = "(age > 10) and (city = 'Boston')";
        expression(x).expect(x);

        let x = "((age > 10) and (city = 'Boston')) or age = 3";
        let y = expression(x).expect(x);

        match *y {
            Expression::Comparison(ref a, ref b, ref c) =>
                {
                    assert_eq!(*a, Operator::Or);
                }
            _ => {
                panic!("NOOO");
            }
        }

    }

    #[test]
    fn test_grouping() {
        expression_grouped("(fname > 0)")
            .expect("Expecting name > 5");
        expression("(fname > 0)")
            .expect("Expecting name > 5");

    }

    #[test]
    fn test_and() {
        //expression_and()
    }

}

<|endoftext|>