<commit_before>#![crate_name = "uu_echo"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_use]
extern crate uucore;

use std::io::{Write, stdout};
use std::str::from_utf8;

#[allow(dead_code)]
static SYNTAX: &'static str = "[OPTIONS]... [STRING]...";
static SUMMARY: &'static str = "display a line of text";
static LONG_HELP: &'static str = r#"
 Echo the STRING(s) to standard output.
 If -e is in effect, the following sequences are recognized:

 \\\\      backslash
 \\a      alert (BEL)
 \\b      backspace
 \\c      produce no further output
 \\e      escape
 \\f      form feed
 \\n      new line
 \\r      carriage return
 \\t      horizontal tab
 \\v      vertical tab
 \\0NNN   byte with octal value NNN (1 to 3 digits)
 \\xHH    byte with hexadecimal value HH (1 to 2 digits)
"#;

#[derive(Clone)]
struct EchoOptions {
    newline: bool,
    escape: bool
}

#[inline(always)]
fn to_char(bytes: &[u8], base: u32) -> char {
    usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
}

fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
    let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
        8 => (3, |c| { (c as char).is_digit(8) }),
        16 => (2, |c| { (c as char).is_digit(16) }),
        _ => panic!(),
    };

    let mut bytes = vec!();
    for offset in 0usize .. max_digits {
        if string.len() <= index + offset as usize {
            break;
        }
        let c = string[index + offset as usize];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            break;
        }
    }

    if bytes.is_empty() {
        (' ', 0)
    } else {
        (to_char(&bytes, base), bytes.len())
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut options = EchoOptions {
        newline: false,
        escape: false
    };

    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("n", "", "do not output the trailing newline")
        .optflag("e", "", "enable interpretation of backslash escapes")
        .optflag("E", "", "disable interpretation of backslash escapes (default)")
        .parse(args);

    options.newline = matches.opt_present("n");
    options.escape = matches.opt_present("e");
    let free = matches.free;
    if !free.is_empty() {
        let string = free.join(" ");
        if options.escape {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            while let Some((index, c)) = iter.next() {
                if !prev_was_slash {
                    if c != '\\' {
                        print!("{}", c);
                    } else {
                        prev_was_slash = true;
                    }
                } else {
                    prev_was_slash = false;
                    match c {
                        '\\' => print!("\\"),
                        'a' => print!("\x07"),
                        'b' => print!("\x08"),
                        'c' => break,
                        'e' => print!("\x1B"),
                        'f' => print!("\x0C"),
                        'n' => print!("\n"),
                        'r' => print!("\r"),
                        't' => print!("\t"),
                        'v' => print!("\x0B"),
                        'x' => {
                            let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
                            if num_char_used == 0 {
                                print!("\\x");
                            } else {
                                print!("{}", c);
                                for _ in 0 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        },
                        '0' => {
                            let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
                            if num_char_used == 0 {
                                print!("\0");
                            } else {
                                print!("{}", c);
                                for _ in 0 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        }
                        _ => {
                            let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
                            if num_char_used == 0 {
                                print!("\\{}", c);
                            } else {
                                print!("{}", esc_c);
                                for _ in 1 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        }
                    }
                }
            }
        } else {
            print!("{}", string);
        }
    }

    if options.newline {
        return_if_err!(1, stdout().flush())
    } else {
        println!()
    }

    0
}
<commit_msg>echo: reorder of match patterns<commit_after>#![crate_name = "uu_echo"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_use]
extern crate uucore;

use std::io::{Write, stdout};
use std::str::from_utf8;

#[allow(dead_code)]
static SYNTAX: &'static str = "[OPTIONS]... [STRING]...";
static SUMMARY: &'static str = "display a line of text";
static LONG_HELP: &'static str = r#"
 Echo the STRING(s) to standard output.
 If -e is in effect, the following sequences are recognized:

 \\\\      backslash
 \\a      alert (BEL)
 \\b      backspace
 \\c      produce no further output
 \\e      escape
 \\f      form feed
 \\n      new line
 \\r      carriage return
 \\t      horizontal tab
 \\v      vertical tab
 \\0NNN   byte with octal value NNN (1 to 3 digits)
 \\xHH    byte with hexadecimal value HH (1 to 2 digits)
"#;

#[derive(Clone)]
struct EchoOptions {
    newline: bool,
    escape: bool
}

#[inline(always)]
fn to_char(bytes: &[u8], base: u32) -> char {
    usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
}

fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
    let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
        8 => (3, |c| { (c as char).is_digit(8) }),
        16 => (2, |c| { (c as char).is_digit(16) }),
        _ => panic!(),
    };

    let mut bytes = vec!();
    for offset in 0usize .. max_digits {
        if string.len() <= index + offset as usize {
            break;
        }
        let c = string[index + offset as usize];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            break;
        }
    }

    if bytes.is_empty() {
        (' ', 0)
    } else {
        (to_char(&bytes, base), bytes.len())
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut options = EchoOptions {
        newline: false,
        escape: false
    };

    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("n", "", "do not output the trailing newline")
        .optflag("e", "", "enable interpretation of backslash escapes")
        .optflag("E", "", "disable interpretation of backslash escapes (default)")
        .parse(args);

    options.newline = matches.opt_present("n");
    options.escape = matches.opt_present("e");
    let free = matches.free;
    if !free.is_empty() {
        let string = free.join(" ");
        if options.escape {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            while let Some((index, c)) = iter.next() {
                if !prev_was_slash {
                    if c != '\\' {
                        print!("{}", c);
                    } else {
                        prev_was_slash = true;
                    }
                } else {
                    prev_was_slash = false;
                    match c {
                        '\\' => print!("\\"),
                        'n' => print!("\n"),
                        'r' => print!("\r"),
                        't' => print!("\t"),
                        'v' => print!("\x0B"),
                        'a' => print!("\x07"),
                        'b' => print!("\x08"),
                        'c' => break,
                        'e' => print!("\x1B"),
                        'f' => print!("\x0C"),
                        'x' => {
                            let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
                            if num_char_used == 0 {
                                print!("\\x");
                            } else {
                                print!("{}", c);
                                for _ in 0 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        },
                        '0' => {
                            let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
                            if num_char_used == 0 {
                                print!("\0");
                            } else {
                                print!("{}", c);
                                for _ in 0 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        }
                        _ => {
                            let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
                            if num_char_used == 0 {
                                print!("\\{}", c);
                            } else {
                                print!("{}", esc_c);
                                for _ in 1 .. num_char_used {
                                    iter.next(); // consume used characters
                                }
                            }
                        }
                    }
                }
            }
        } else {
            print!("{}", string);
        }
    }

    if options.newline {
        return_if_err!(1, stdout().flush())
    } else {
        println!()
    }

    0
}
<|endoftext|>


<commit_before>// Kevin Cantu
// replace djb with murmur

use std;
use vec2;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016x%016x", mm[0u], mm[1u]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);

   // TODO: random seeds
   let seed = 0u64;
   let h1 = seed;
   let h2 = seed;

   let c1 = 0x_87c37b91114253d5_u64;
   let c2 = 0x_4cf5ad432745937f_u64;

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      ret vec::foldl(0u64, bb, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   #[should_fail]
   fn test1_conversion_u8to64 () {
      let _XXXX = convert_u8to64 ([1u8,2u8]);
   }

   #[test]
   fn test2_conversion_u8to64 () {
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
      let test2 = convert_u8to64 (aa+aa);
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <copy TT> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // split into vector^2
      fn splitEvery <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];

         vec::iteri (xs, {|ii, _x|
            let len = vec::len(xs);

            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });

         ret ys;
      }

      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   // split body data and tail
   let nbytes  = vec::len(key);
   let nblocks = nbytes / 16u;
   let (blocks_, tail) = vec2::splitAt (nblocks*16u, key);
   let blocks: [u64] = convert_u8to64 (blocks_);

   // crunch body data
   let ii = 0u;
   assert nblocks % 2u == 0u;
   while (ii < nblocks) {

      let k1 = blocks[ii*2u+0u];
      let k2 = blocks[ii*2u+1u];

      k1 *= c1;
      k1 = rotl64(k1, 31u64);
      k1 *= c2;
      h1 ^= k1;

      h1 = rotl64(h1, 27u64);
      h1 += h2;
      h1 = h1*5u64 + 0x_52dce729_u64;

      k2 *= c2;
      k2 = rotl64(k2, 33u64);
      k2 *= c1;
      h2 ^= k2;

      h2 = rotl64(h2, 31u64);
      h2 += h1;
      h2 = h2*5u64 + 0x_38495ab5_u64;

      ii += 1u;
   }

   // tail
   vec::grow(tail, 16u - vec::len(tail), 0u8);
   assert vec::len(tail) == 16u;
   let jj = vec::reversed (tail);
   let jj_ = convert_u8to64 (jj);
   assert vec::len(jj_) == 2u;
   let j1 = jj_[1u]; // reversing
   let j2 = jj_[0u]; // reversing

   j2 *= c2;
   j2 = rotl64(j2, 33u);
   j2 *= c1;
   h2 ^= j2;

   j1 *= c1;
   j1 = rotl64(j1, 31u);
   j1 *= c2;
   h1 ^= j1;

   // finalization

   h1 ^= nbytes;
   h2 ^= nbytes;

   h1 += h2;
   h2 += h1;

   h1 = fmix(h1);
   h2 = fmix(h2);

   h1 += h2;
   h2 += h1;

   ret [h1, h2];
   //ret test2;
}

<commit_msg>hmmmm<commit_after>// Kevin Cantu
// replace djb with murmur

use std;
use vec2;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016x%016x", mm[0u], mm[1u]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);

   // TODO: random seeds
   let seed = 0u64;
   let h1 = seed;
   let h2 = seed;

   let c1 = 0x_87c37b91114253d5_u64;
   let c2 = 0x_4cf5ad432745937f_u64;

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      ret vec::foldl(0u64, bb, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   #[should_fail]
   fn test1_conversion_u8to64 () {
      let _XXXX = convert_u8to64 ([1u8,2u8]);
   }

   #[test]
   fn test2_conversion_u8to64 () {
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
      let _test2 = convert_u8to64 (aa+aa);
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <copy TT> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // split into vector^2
      fn splitEvery <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];

         vec::iteri (xs, {|ii, _x|
            let len = vec::len(xs);

            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });

         ret ys;
      }

      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   // split body data and tail
   let nbytes  = vec::len(key);
   let nblocks = nbytes / 16u;
   let (body_, tail) = vec2::splitAt (nblocks*16u, key);
   let body: [u64] = convert_u8to64 (body_);

   fn apply_constants_A (rot: u64,
                         kk: u64,
                         h: u64,
                         c: u64,
                         c_: u64) -> u64 {
      let k = kk;
      k *= c;
      k  = rotl64(k, rot);
      k *= c_;
      ret h ^ k;
   }

   // crunch body data
   fn do_body (blocks: [u64],
               nblocks: uint,
               h1: u64,
               h2: u64,
               c1: u64,
               c2: u64) -> (u64,u64) {

      let ii = 0u;
      assert nblocks % 2u == 0u;
      while (ii < nblocks) {

         let k1 = blocks[ii*2u + 0u];
         let k2 = blocks[ii*2u + 1u];

         let h1 = apply_constants_A (31u64, k1, h1, c1, c2);

         h1 = rotl64(h1, 27u64);
         h1 += h2;
         h1 = h1*5u64 + 0x_52dce729_u64;

         let h2 = apply_constants_A (33u64, k2, h2, c2, c1);

         h2 = rotl64(h2, 31u64);
         h2 += h1;
         h2 = h2*5u64 + 0x_38495ab5_u64;

         ii += 1u;
      }

      ret (h1, h2);
   }

   let (h1,h2) = do_body (body, nblocks, h1, h2, c1, c2);

   // tail
   fn do_tail (tail_: [u8], h1: u64, h2: u64, c1: u64, c2: u64) -> (u64,u64) {
      let tail = tail_;
      vec::grow(tail, 16u - vec::len(tail), 0u8);
      assert vec::len(tail) == 16u;
      let jj = vec::reversed (tail);
      let jj_ = convert_u8to64 (jj);
      assert vec::len(jj_) == 2u;
      let j1 = jj_[1u]; // reversing
      let j2 = jj_[0u]; // reversing

      let h2_ = apply_constants_A (33u64, j2, h2, c2, c1);
      let h1_ = apply_constants_A (31u64, j1, h1, c1, c2);
      ret (h1_,h2_);
   }

   let (h1,h2) = do_tail (tail, h1, h2, c1, c2);

   // finalization
   fn finalize (h1_: u64, h2_: u64, len: uint) -> (u64,u64) {
      let h1 = h1_;
      let h2 = h2_;

      h1 ^= len as u64;
      h2 ^= len as u64;

      h1 += h2;
      h2 += h1;

      h1 = fmix(h1);
      h2 = fmix(h2);

      h1 += h2;
      h2 += h1;

      ret (h1, h2);
   }

   let (h1, h2) = finalize (h1, h2, nbytes);

   ret [h1, h2];
   //ret test2;
}

<|endoftext|>


<commit_before>use cgmath::Point3;

use aabb::AABB;
use renderer::{Intersect, RTTriangle, Ray};

pub struct BVHNode {
    aabb: AABB,
    pub start_i: usize,
    pub end_i: usize,
    left_child_i: Option<usize>,
    right_child_i: Option<usize>,
}

impl BVHNode {
    fn new(indices: &[usize], aabbs: &[AABB], start_i: usize, end_i: usize) -> BVHNode {
        let mut node = BVHNode {
            aabb: aabbs[indices[start_i]].clone(),
            start_i, end_i,
            left_child_i: None, right_child_i: None
        };
        for &i in indices[(start_i + 1)..end_i].iter() {
            node.aabb.add_aabb(&aabbs[i]);
        }
        node
    }

    fn size(&self) -> usize {
        self.end_i - self.start_i
    }

    pub fn is_leaf(&self) -> bool {
        self.left_child_i.is_none()
    }
}

impl<'a> Intersect<'a, f32> for BVHNode {
    fn intersect(&self, ray: &Ray) -> Option<f32> {
        self.aabb.intersect(ray)
    }
}

const MAX_LEAF_SIZE: usize = 8;

pub struct BVH {
    nodes: Vec<BVHNode>,
}

impl BVH {
    pub fn empty() -> BVH {
        BVH { nodes: Vec::new() }
    }

    pub fn build_object_median(triangles: &mut Vec<RTTriangle>) -> BVH {
        let mut indices: Vec<usize> = (0..triangles.len()).collect();
        let aabbs: Vec<AABB> = triangles.iter().map(|t| t.aabb()).collect();
        let centers: Vec<Point3<f32>> = triangles.into_iter().map(|t| t.center()).collect();
        let mut nodes = Vec::with_capacity(f32::log2(triangles.len() as f32) as usize);
        nodes.push(BVHNode::new(&indices, &aabbs, 0, triangles.len()));
        let mut split_stack = vec![0usize];

        while let Some(node_i) = split_stack.pop() {
            let start_i = nodes[node_i].start_i;
            let end_i = nodes[node_i].end_i;
            let axis_i = nodes[node_i].aabb.longest_edge_i();
            indices[start_i..end_i]
                .sort_unstable_by(|&i1, &i2| {
                    let c1 = centers[i1][axis_i];
                    let c2 = centers[i2][axis_i];
                    c1.partial_cmp(&c2).unwrap()
                });
            let mid_i = (start_i + end_i) / 2;

            let left_child = BVHNode::new(&indices, &aabbs, start_i, mid_i);
            nodes[node_i].left_child_i = Some(nodes.len());
            if left_child.size() > MAX_LEAF_SIZE {
                split_stack.push(nodes.len());
            }
            nodes.push(left_child);

            let right_child = BVHNode::new(&indices, &aabbs, mid_i, end_i);
            nodes[node_i].right_child_i = Some(nodes.len());
            if right_child.size() > MAX_LEAF_SIZE {
                split_stack.push(nodes.len());
            }
            nodes.push(right_child);
        }

        // Make triangles ordering match indices ordering
        // TODO: This could be done better
        *triangles = indices.iter().map(|&i| triangles[i].clone()).collect();
        nodes.shrink_to_fit();
        BVH { nodes }
    }

    pub fn get_children(&self, node: &BVHNode) -> Option<(&BVHNode, &BVHNode)> {
        let left = if let Some(left_i) = node.left_child_i {
            &self.nodes[left_i]
        } else {
            return None;
        };
        let right = if let Some(right_i) = node.right_child_i {
            &self.nodes[right_i]
        } else {
            return None;
        };
        Some((left, right))
    }

    pub fn root(&self) -> &BVHNode {
        &self.nodes[0]
    }

    pub fn size(&self) -> usize {
        self.nodes.len()
    }
}
<commit_msg>Remove unused function<commit_after>use cgmath::Point3;

use aabb::AABB;
use renderer::{Intersect, RTTriangle, Ray};

pub struct BVHNode {
    aabb: AABB,
    pub start_i: usize,
    pub end_i: usize,
    left_child_i: Option<usize>,
    right_child_i: Option<usize>,
}

impl BVHNode {
    fn new(indices: &[usize], aabbs: &[AABB], start_i: usize, end_i: usize) -> BVHNode {
        let mut node = BVHNode {
            aabb: aabbs[indices[start_i]].clone(),
            start_i, end_i,
            left_child_i: None, right_child_i: None
        };
        for &i in indices[(start_i + 1)..end_i].iter() {
            node.aabb.add_aabb(&aabbs[i]);
        }
        node
    }

    fn size(&self) -> usize {
        self.end_i - self.start_i
    }

    pub fn is_leaf(&self) -> bool {
        self.left_child_i.is_none()
    }
}

impl<'a> Intersect<'a, f32> for BVHNode {
    fn intersect(&self, ray: &Ray) -> Option<f32> {
        self.aabb.intersect(ray)
    }
}

const MAX_LEAF_SIZE: usize = 8;

pub struct BVH {
    nodes: Vec<BVHNode>,
}

impl BVH {
    pub fn empty() -> BVH {
        BVH { nodes: Vec::new() }
    }

    pub fn build_object_median(triangles: &mut Vec<RTTriangle>) -> BVH {
        let mut indices: Vec<usize> = (0..triangles.len()).collect();
        let aabbs: Vec<AABB> = triangles.iter().map(|t| t.aabb()).collect();
        let centers: Vec<Point3<f32>> = triangles.into_iter().map(|t| t.center()).collect();
        let mut nodes = Vec::with_capacity(f32::log2(triangles.len() as f32) as usize);
        nodes.push(BVHNode::new(&indices, &aabbs, 0, triangles.len()));
        let mut split_stack = vec![0usize];

        while let Some(node_i) = split_stack.pop() {
            let start_i = nodes[node_i].start_i;
            let end_i = nodes[node_i].end_i;
            let axis_i = nodes[node_i].aabb.longest_edge_i();
            indices[start_i..end_i]
                .sort_unstable_by(|&i1, &i2| {
                    let c1 = centers[i1][axis_i];
                    let c2 = centers[i2][axis_i];
                    c1.partial_cmp(&c2).unwrap()
                });
            let mid_i = (start_i + end_i) / 2;

            let left_child = BVHNode::new(&indices, &aabbs, start_i, mid_i);
            nodes[node_i].left_child_i = Some(nodes.len());
            if left_child.size() > MAX_LEAF_SIZE {
                split_stack.push(nodes.len());
            }
            nodes.push(left_child);

            let right_child = BVHNode::new(&indices, &aabbs, mid_i, end_i);
            nodes[node_i].right_child_i = Some(nodes.len());
            if right_child.size() > MAX_LEAF_SIZE {
                split_stack.push(nodes.len());
            }
            nodes.push(right_child);
        }

        // Make triangles ordering match indices ordering
        // TODO: This could be done better
        *triangles = indices.iter().map(|&i| triangles[i].clone()).collect();
        nodes.shrink_to_fit();
        BVH { nodes }
    }

    pub fn get_children(&self, node: &BVHNode) -> Option<(&BVHNode, &BVHNode)> {
        let left = if let Some(left_i) = node.left_child_i {
            &self.nodes[left_i]
        } else {
            return None;
        };
        let right = if let Some(right_i) = node.right_child_i {
            &self.nodes[right_i]
        } else {
            return None;
        };
        Some((left, right))
    }

    pub fn root(&self) -> &BVHNode {
        &self.nodes[0]
    }
}
<|endoftext|>


<commit_before>//!
//! The lex tool generates lexer tools from its input
//!

use std::result::Result;
use std::error::Error;
use std::iter::*;
use serde::*;
use serde_json::*;
use concordance::*;
use silkthread_base::*;
use silkthread_base::basic::*;
use silkthread_base::basic::tool_name::*;

///
/// Input for the lexer tool
///
#[derive(Serialize, Deserialize)]
pub struct LexToolInput {
    /// Name of the tool that the lexer will define
    pub new_tool_name:  String,

    /// The symbols that the lexer will match
    pub symbols:        Vec<LexToolSymbol>
}

///
/// Represents a lexer match
///
#[derive(Serialize, Deserialize)]
pub struct LexerMatch {
    /// Token that was matched
    pub token:      String,

    /// Phrase that was matched from the input
    pub matched:    String,

    /// Start of the match
    pub start:      i32,

    /// End of the match
    pub end:        i32
}

///
/// Lexer symbol
///
#[derive(Serialize, Deserialize)]
pub struct LexToolSymbol {
    /// The name of the symbol that will be generated if this match is made
    pub symbol_name:    String,

    /// The rule that will be matched against this symbol
    pub match_rule:     String
}

///
/// Lexer generation tool
///
pub struct LexTool {
}

impl LexTool {
    ///
    /// Creates a new lexer tool
    ///
    pub fn new() -> LexTool {
        LexTool { }
    }

    ///
    /// Converts a string containing a lexer regex into a concordance pattern
    ///
    pub fn pattern_for_string(regex: &str) -> Pattern<char> {
        // We'll process the regex as UTF-16 code points
        let regex_chars: Vec<char> = regex.chars().collect();

        // Go on to build the pattern
        LexTool::pattern_for_chars(&regex_chars)
    }

    ///
    /// Returns a substitute character for a character following a '\'
    ///
    fn special_character_char(c: char) -> char {
        match c {
            'n' => '\n',
            'r' => '\r',
            't' => '\t',
            '\\' => '\\',
            'w' => ' ',

            // Just the literal character if there's no match
            c => c
        }
    }

    ///
    /// Returns the pattern to use for a special character
    ///
    fn special_character_pattern(c: char) -> Pattern<char> {
        match c {
            // Any whitespace
            'w' => MatchAny(vec![
                Match(vec![' ']),
                Match(vec!['\t']),
                Match(vec!['\n']),
                Match(vec!['\r']),
                Match(vec!['\u{0085}']),
                Match(vec!['\u{00a0}']),
                Match(vec!['\u{1680}']),
                MatchRange('\u{2000}', '\u{200a}'),
                Match(vec!['\u{2028}']),
                Match(vec!['\u{2029}']),
                Match(vec!['\u{202f}']),
                Match(vec!['\u{205f}']),
                Match(vec!['\u{3000}'])
            ]),

            // Just the literal character otherwise
            c => Match(vec![LexTool::special_character_char(c)])
        }
    }

    ///
    /// Finds a subpattern from the index of the '(' that starts it
    ///
    fn get_subpattern<'a>(regex: &'a [char], subpattern_start: usize) -> &'a [char] {
        let start_pos   = subpattern_start+1;
        let mut depth   = 1;
        let mut end_pos = start_pos;
        let regex_len   = regex.len();

        // Subpattern ends at the end of the regex or at the closing ')'
        while end_pos < regex_len && depth > 0 {
            let chr = regex[end_pos];

            match chr {
                '(' => depth += 1,
                ')' => {
                    depth -= 1;
                    if depth == 0 {
                        break;
                    }
                }
                '\\' => end_pos += 1,
                '[' => {
                    // '[)]' isn't a close bracket :-/
                    while end_pos < regex_len && regex[end_pos] != ']' {
                        if regex[end_pos] == '\\' {
                            end_pos += 1;
                        }
                        end_pos += 1;
                    }
                }

                _ => ()
            }

            end_pos += 1;
        }

        &regex[start_pos..end_pos]
    }

    ///
    /// Joins up any sequence of Match<x>, Match<y>
    ///
    fn join_matches(pattern: &mut Vec<Pattern<char>>) {
        let mut index = 1;

        while index < pattern.len() {
            let current = pattern[index].clone();

            if let Match(ref current) = current {
                let previous = pattern[index-1].clone();

                if let Match(ref previous) = previous {
                    // If we have two Matches one after the other, combine them into a phrase
                    // This and some other parts of this code can be improved by concatenating phrases all at once or by building into a new pattern array
                    let mut phrase = previous.clone();
                    phrase.extend(current);

                    pattern[index-1] = Match(phrase);
                    pattern.remove(index);

                    index -= 1;
                }
            }

            index += 1;
        }
    }

    ///
    /// Builds a pattern from a UTF-16 slice
    ///
    pub fn pattern_for_chars(regex: &[char]) -> Pattern<char> {
        // Characters to match exactly as built up so far
        let mut pattern         = vec![];
        let mut or_positions    = vec![];

        // Go through the slice and build up a regex
        let mut pos     = 0;
        let regex_len   = regex.len();

        while pos < regex_len {
            match regex[pos] {
                '\\' => {
                    // Quoted character
                    pos += 1;
                    if pos < regex_len {
                        pattern.push(LexTool::special_character_pattern(regex[pos]))
                    }
                },

                '.' => {
                    // Anything
                    pattern.push(MatchRange('\u{0000}', '\u{10ffff}'))
                },

                '*' => {
                    // Last item repeated
                    let pattern_len = pattern.len();
                    if pattern_len > 0 {
                        if let Some(last) = pattern.last().map(|x| x.clone()) {
                            pattern[pattern_len-1] = RepeatInfinite(0, Box::new(last));
                        }
                    }
                },

                '+' => {
                    // Last item at least once and then repeated
                    let pattern_len = pattern.len();
                    if pattern_len > 0 {
                        if let Some(last) = pattern.last().map(|x| x.clone()) {
                            pattern[pattern_len-1] = RepeatInfinite(1, Box::new(last));
                        }
                    }
                },

                '[' => {
                    // Character ranges
                    let mut ranges = vec![];
                    pos += 1;

                    let mut last_char = None;
                    while pos < regex_len && regex[pos] != ']' {
                        let mut next_char = regex[pos];

                        if next_char == '\\' && pos+1 < regex_len {
                            pos += 1;
                            next_char = LexTool::special_character_char(regex[pos]);
                        }

                        if next_char == '-' && pos < regex_len-1 {
                            pos += 1;
                            let final_char = regex[pos];

                            if let Some(last_char) = last_char {
                                ranges.last_mut().map(|x| *x = (last_char, final_char));
                            }
                        } else {
                            last_char = Some(next_char);
                            ranges.push((next_char, next_char));
                        }

                        pos += 1;
                    }

                    if ranges.len() == 1 {
                        let (first, last) = ranges[0];
                        pattern.push(MatchRange(first, last));
                    } else {
                        pattern.push(MatchAny(ranges.iter().map(|&(first, last)| MatchRange(first, last)).collect()));
                    }
                },

                '|' => {
                    // We'll join the two sides of the 'or' later on
                    or_positions.push(pattern.len());
                },

                '(' => {
                    // Subpattern
                    let subpattern = LexTool::get_subpattern(regex, pos);
                    pattern.push(LexTool::pattern_for_chars(subpattern));

                    pos += subpattern.len()+1;
                },

                c => {
                    // Just match this character
                    pattern.push(Match(vec![c]));
                }
            }

            // Next character
            pos += 1;
        }

        // Join up any subpatterns affected by the 'or' operator
        let mut offset = 0;
        for position_of_or in or_positions {
            if position_of_or > 0 {
                let actual_pos      = position_of_or-offset;
                let (left, right)   = (pattern[actual_pos-1].clone(), pattern[actual_pos].clone());

                pattern.remove(actual_pos);
                pattern[actual_pos-1] = MatchAny(vec![left, right]);

                offset += 1;
            }
        }

        // Join up plain matches
        LexTool::join_matches(&mut pattern);

        // Pattern that we've matched
        if pattern.len() == 0 {
            Epsilon
        } else if pattern.len() == 1 {
            pattern[0].clone()
        } else {
            MatchAll(pattern)
        }
    }
}

impl Tool for LexTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        // Attempt to parse the input
        let lex_defn = from_value::<LexToolInput>(input);

        // Fetch the tool for defining new tools in this environment
        let define_tool: Result<TypedTool<DefineToolInput, ()>, RetrieveToolError> = environment.get_json_tool(DEFINE_TOOL).map(|tool| TypedTool::from(tool));

        match (lex_defn, define_tool) {
            (Err(erm), _) => {
                // Fail if the input value doesn't deserialize
                Err(json![{
                    "error":        "Parameters incorrect",
                    "description":  erm.description()
                }])
            },

            (_, Err(erm)) => {
                // Fail if there's no define tool
                Err(json![{
                    "error":        "Could not retrieve define-tool",
                    "description":  erm.message()
                }])
            },

            (Ok(lex_defn), Ok(define_tool)) => {
                // Generate a lexer tool for this definition
                let lexer_tool = StringLexingTool::from_lex_tool_input(&lex_defn);

                // Create an environment with just the tool
                let lexer_toolset   = BasicToolSet::from(vec![ ("lex", lexer_tool) ]);
                let lexer_env       = StaticEnvironment::from_toolset(lexer_toolset, &EmptyEnvironment::new());

                // Define it in the environment
                define_tool.invoke(DefineToolInput::new("new", Some(&lex_defn.new_tool_name)), &lexer_env).map(|_| Value::Null)
            }
        }
    }
}

///
/// Tool that reads a string and generates a lexed array of matches
///
pub struct StringLexingTool {
    matcher: TokenMatcher<char, String>
}

impl StringLexingTool {
    ///
    /// Creates a lexer tool from a definition
    ///
    pub fn from_lex_tool_input(lex_defn: &LexToolInput) -> StringLexingTool {
        // Generate a token matcher from the lexer
        let mut token_matcher = TokenMatcher::new();

        for symbol in lex_defn.symbols.iter() {
            token_matcher.add_pattern(LexTool::pattern_for_string(&symbol.match_rule), symbol.symbol_name.clone());
        }

        token_matcher.prepare_to_match();

        // This is what we use in the lexing tool
        StringLexingTool { matcher: token_matcher }
    }
}

impl Tool for StringLexingTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        if let Value::String(input) = input {
            // Input must be a simple string

            // Start tokenizing it
            let mut tokenizer   = Tokenizer::new(input.read_symbols(), &self.matcher);
            let mut result      = vec![];

            while let Some((range, token)) = tokenizer.next() {
                result.push(json![ {
                    "token":    token,
                    "matched":  input[range.clone()],
                    "start":    range.start,
                    "end":      range.end
                } ]);
            }

            // Final result is an array of tokens
            Ok(Value::Array(result))
        } else {
            Err(json![{
                "error": "Input must be a string"
            }])
        }
    }
}

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

    #[test]
    fn can_create_phrase_match() {
        assert!(LexTool::pattern_for_string("phrase") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_any_pattern() {
        assert!(LexTool::pattern_for_string(".*") == RepeatInfinite(0, Box::new(MatchRange('\u{0000}', '\u{10ffff}'))));
    }

    #[test]
    fn can_create_or_match() {
        assert!(LexTool::pattern_for_string("a|b") == MatchAny(vec![ Match(vec!['a']), Match(vec!['b']) ]));
    }

    #[test]
    fn can_create_nested_or_match() {
        assert!(LexTool::pattern_for_string("a|b|c") == MatchAny(vec![ MatchAny(vec![ Match(vec!['a']), Match(vec!['b']) ]), Match(vec!['c'])] ));
    }

    #[test]
    fn can_create_grouped_or_match() {
        assert!(LexTool::pattern_for_string("(foo)|(bar)") == MatchAny(vec![ Match(vec!['f', 'o', 'o']), Match(vec!['b', 'a', 'r']) ]));
    }

    #[test]
    fn or_is_processed_early() {
        assert!(LexTool::pattern_for_string("foo|bar") == MatchAll(vec![ Match(vec!['f', 'o']), MatchAny(vec![ Match(vec!['o']), Match(vec!['b']) ]), Match(vec!['a', 'r']) ]));
    }

    #[test]
    fn can_create_simple_grouping() {
        assert!(LexTool::pattern_for_string("(phrase)") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_nested_grouping() {
        assert!(LexTool::pattern_for_string("(p(h(r)a)s)e") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_match_one() {
        assert!(LexTool::pattern_for_string("[a]") == MatchRange('a', 'a'));
    }

    #[test]
    fn can_interpret_newline_quote_characters() {
        assert!(LexTool::pattern_for_string("\\n") == Match(vec![ '\n' ]));
    }

    #[test]
    fn can_create_match_range() {
        assert!(LexTool::pattern_for_string("[a-z]") == MatchRange('a', 'z'));
    }

    #[test]
    fn can_create_match_set() {
        assert!(LexTool::pattern_for_string("[acgh]") == MatchAny(vec![ MatchRange('a', 'a'), MatchRange('c', 'c'), MatchRange('g', 'g'), MatchRange('h', 'h') ]));
    }

    #[test]
    fn can_create_match_multi_range() {
        assert!(LexTool::pattern_for_string("[a-zA-Z]") == MatchAny(vec![ MatchRange('a', 'z'), MatchRange('A', 'Z') ]));
    }

    #[test]
    fn can_create_match_set_and_range() {
        assert!(LexTool::pattern_for_string("[aA-Z]") == MatchAny(vec![ MatchRange('a', 'a'), MatchRange('A', 'Z') ]));
    }
}

<commit_msg>Add a test for our new lexer generator<commit_after>//!
//! The lex tool generates lexer tools from its input
//!

use std::result::Result;
use std::error::Error;
use std::iter::*;
use serde::*;
use serde_json::*;
use concordance::*;
use silkthread_base::*;
use silkthread_base::basic::*;
use silkthread_base::basic::tool_name::*;

///
/// Input for the lexer tool
///
#[derive(Serialize, Deserialize)]
pub struct LexToolInput {
    /// Name of the tool that the lexer will define
    pub new_tool_name:  String,

    /// The symbols that the lexer will match
    pub symbols:        Vec<LexToolSymbol>
}

///
/// Lexer symbol
///
#[derive(Serialize, Deserialize)]
pub struct LexToolSymbol {
    /// The name of the symbol that will be generated if this match is made
    pub symbol_name:    String,

    /// The rule that will be matched against this symbol
    pub match_rule:     String
}

///
/// Represents a lexer match
///
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)]
pub struct LexerMatch {
    /// Token that was matched
    pub token:      String,

    /// Phrase that was matched from the input
    pub matched:    String,

    /// Start of the match
    pub start:      i32,

    /// End of the match
    pub end:        i32
}

///
/// Lexer generation tool
///
pub struct LexTool {
}

impl LexTool {
    ///
    /// Creates a new lexer tool
    ///
    pub fn new() -> LexTool {
        LexTool { }
    }

    ///
    /// Converts a string containing a lexer regex into a concordance pattern
    ///
    pub fn pattern_for_string(regex: &str) -> Pattern<char> {
        // We'll process the regex as UTF-16 code points
        let regex_chars: Vec<char> = regex.chars().collect();

        // Go on to build the pattern
        LexTool::pattern_for_chars(&regex_chars)
    }

    ///
    /// Returns a substitute character for a character following a '\'
    ///
    fn special_character_char(c: char) -> char {
        match c {
            'n' => '\n',
            'r' => '\r',
            't' => '\t',
            '\\' => '\\',
            'w' => ' ',

            // Just the literal character if there's no match
            c => c
        }
    }

    ///
    /// Returns the pattern to use for a special character
    ///
    fn special_character_pattern(c: char) -> Pattern<char> {
        match c {
            // Any whitespace
            'w' => MatchAny(vec![
                Match(vec![' ']),
                Match(vec!['\t']),
                Match(vec!['\n']),
                Match(vec!['\r']),
                Match(vec!['\u{0085}']),
                Match(vec!['\u{00a0}']),
                Match(vec!['\u{1680}']),
                MatchRange('\u{2000}', '\u{200a}'),
                Match(vec!['\u{2028}']),
                Match(vec!['\u{2029}']),
                Match(vec!['\u{202f}']),
                Match(vec!['\u{205f}']),
                Match(vec!['\u{3000}'])
            ]),

            // Just the literal character otherwise
            c => Match(vec![LexTool::special_character_char(c)])
        }
    }

    ///
    /// Finds a subpattern from the index of the '(' that starts it
    ///
    fn get_subpattern<'a>(regex: &'a [char], subpattern_start: usize) -> &'a [char] {
        let start_pos   = subpattern_start+1;
        let mut depth   = 1;
        let mut end_pos = start_pos;
        let regex_len   = regex.len();

        // Subpattern ends at the end of the regex or at the closing ')'
        while end_pos < regex_len && depth > 0 {
            let chr = regex[end_pos];

            match chr {
                '(' => depth += 1,
                ')' => {
                    depth -= 1;
                    if depth == 0 {
                        break;
                    }
                }
                '\\' => end_pos += 1,
                '[' => {
                    // '[)]' isn't a close bracket :-/
                    while end_pos < regex_len && regex[end_pos] != ']' {
                        if regex[end_pos] == '\\' {
                            end_pos += 1;
                        }
                        end_pos += 1;
                    }
                }

                _ => ()
            }

            end_pos += 1;
        }

        &regex[start_pos..end_pos]
    }

    ///
    /// Joins up any sequence of Match<x>, Match<y>
    ///
    fn join_matches(pattern: &mut Vec<Pattern<char>>) {
        let mut index = 1;

        while index < pattern.len() {
            let current = pattern[index].clone();

            if let Match(ref current) = current {
                let previous = pattern[index-1].clone();

                if let Match(ref previous) = previous {
                    // If we have two Matches one after the other, combine them into a phrase
                    // This and some other parts of this code can be improved by concatenating phrases all at once or by building into a new pattern array
                    let mut phrase = previous.clone();
                    phrase.extend(current);

                    pattern[index-1] = Match(phrase);
                    pattern.remove(index);

                    index -= 1;
                }
            }

            index += 1;
        }
    }

    ///
    /// Builds a pattern from a UTF-16 slice
    ///
    pub fn pattern_for_chars(regex: &[char]) -> Pattern<char> {
        // Characters to match exactly as built up so far
        let mut pattern         = vec![];
        let mut or_positions    = vec![];

        // Go through the slice and build up a regex
        let mut pos     = 0;
        let regex_len   = regex.len();

        while pos < regex_len {
            match regex[pos] {
                '\\' => {
                    // Quoted character
                    pos += 1;
                    if pos < regex_len {
                        pattern.push(LexTool::special_character_pattern(regex[pos]))
                    }
                },

                '.' => {
                    // Anything
                    pattern.push(MatchRange('\u{0000}', '\u{10ffff}'))
                },

                '*' => {
                    // Last item repeated
                    let pattern_len = pattern.len();
                    if pattern_len > 0 {
                        if let Some(last) = pattern.last().map(|x| x.clone()) {
                            pattern[pattern_len-1] = RepeatInfinite(0, Box::new(last));
                        }
                    }
                },

                '+' => {
                    // Last item at least once and then repeated
                    let pattern_len = pattern.len();
                    if pattern_len > 0 {
                        if let Some(last) = pattern.last().map(|x| x.clone()) {
                            pattern[pattern_len-1] = RepeatInfinite(1, Box::new(last));
                        }
                    }
                },

                '[' => {
                    // Character ranges
                    let mut ranges = vec![];
                    pos += 1;

                    let mut last_char = None;
                    while pos < regex_len && regex[pos] != ']' {
                        let mut next_char = regex[pos];

                        if next_char == '\\' && pos+1 < regex_len {
                            pos += 1;
                            next_char = LexTool::special_character_char(regex[pos]);
                        }

                        if next_char == '-' && pos < regex_len-1 {
                            pos += 1;
                            let final_char = regex[pos];

                            if let Some(last_char) = last_char {
                                ranges.last_mut().map(|x| *x = (last_char, final_char));
                            }
                        } else {
                            last_char = Some(next_char);
                            ranges.push((next_char, next_char));
                        }

                        pos += 1;
                    }

                    if ranges.len() == 1 {
                        let (first, last) = ranges[0];
                        pattern.push(MatchRange(first, last));
                    } else {
                        pattern.push(MatchAny(ranges.iter().map(|&(first, last)| MatchRange(first, last)).collect()));
                    }
                },

                '|' => {
                    // We'll join the two sides of the 'or' later on
                    or_positions.push(pattern.len());
                },

                '(' => {
                    // Subpattern
                    let subpattern = LexTool::get_subpattern(regex, pos);
                    pattern.push(LexTool::pattern_for_chars(subpattern));

                    pos += subpattern.len()+1;
                },

                c => {
                    // Just match this character
                    pattern.push(Match(vec![c]));
                }
            }

            // Next character
            pos += 1;
        }

        // Join up any subpatterns affected by the 'or' operator
        let mut offset = 0;
        for position_of_or in or_positions {
            if position_of_or > 0 {
                let actual_pos      = position_of_or-offset;
                let (left, right)   = (pattern[actual_pos-1].clone(), pattern[actual_pos].clone());

                pattern.remove(actual_pos);
                pattern[actual_pos-1] = MatchAny(vec![left, right]);

                offset += 1;
            }
        }

        // Join up plain matches
        LexTool::join_matches(&mut pattern);

        // Pattern that we've matched
        if pattern.len() == 0 {
            Epsilon
        } else if pattern.len() == 1 {
            pattern[0].clone()
        } else {
            MatchAll(pattern)
        }
    }
}

impl Tool for LexTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        // Attempt to parse the input
        let lex_defn = from_value::<LexToolInput>(input);

        // Fetch the tool for defining new tools in this environment
        let define_tool: Result<TypedTool<DefineToolInput, ()>, RetrieveToolError> = environment.get_json_tool(DEFINE_TOOL).map(|tool| TypedTool::from(tool));

        match (lex_defn, define_tool) {
            (Err(erm), _) => {
                // Fail if the input value doesn't deserialize
                Err(json![{
                    "error":        "Parameters incorrect",
                    "description":  erm.description()
                }])
            },

            (_, Err(erm)) => {
                // Fail if there's no define tool
                Err(json![{
                    "error":        "Could not retrieve define-tool",
                    "description":  erm.message()
                }])
            },

            (Ok(lex_defn), Ok(define_tool)) => {
                // Generate a lexer tool for this definition
                let lexer_tool = StringLexingTool::from_lex_tool_input(&lex_defn);

                // Create an environment with just the tool
                let lexer_toolset   = BasicToolSet::from(vec![ ("lex", lexer_tool) ]);
                let lexer_env       = StaticEnvironment::from_toolset(lexer_toolset, &EmptyEnvironment::new());

                // Define it in the environment
                define_tool.invoke(DefineToolInput::new("new", Some(&lex_defn.new_tool_name)), &lexer_env).map(|_| Value::Null)
            }
        }
    }
}

///
/// Tool that reads a string and generates a lexed array of matches
///
pub struct StringLexingTool {
    matcher: TokenMatcher<char, String>
}

impl StringLexingTool {
    ///
    /// Creates a lexer tool from a definition
    ///
    pub fn from_lex_tool_input(lex_defn: &LexToolInput) -> StringLexingTool {
        // Generate a token matcher from the lexer
        let mut token_matcher = TokenMatcher::new();

        for symbol in lex_defn.symbols.iter() {
            token_matcher.add_pattern(LexTool::pattern_for_string(&symbol.match_rule), symbol.symbol_name.clone());
        }

        token_matcher.prepare_to_match();

        // This is what we use in the lexing tool
        StringLexingTool { matcher: token_matcher }
    }
}

impl Tool for StringLexingTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        if let Value::String(input) = input {
            // Input must be a simple string

            // Start tokenizing it
            let mut tokenizer   = Tokenizer::new(input.read_symbols(), &self.matcher);
            let mut result      = vec![];

            while let Some((range, token)) = tokenizer.next() {
                result.push(json![ {
                    "token":    token,
                    "matched":  input[range.clone()],
                    "start":    range.start,
                    "end":      range.end
                } ]);
            }

            // Final result is an array of tokens
            Ok(Value::Array(result))
        } else {
            Err(json![{
                "error": "Input must be a string"
            }])
        }
    }
}

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

    #[test]
    fn can_create_phrase_match() {
        assert!(LexTool::pattern_for_string("phrase") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_any_pattern() {
        assert!(LexTool::pattern_for_string(".*") == RepeatInfinite(0, Box::new(MatchRange('\u{0000}', '\u{10ffff}'))));
    }

    #[test]
    fn can_create_or_match() {
        assert!(LexTool::pattern_for_string("a|b") == MatchAny(vec![ Match(vec!['a']), Match(vec!['b']) ]));
    }

    #[test]
    fn can_create_nested_or_match() {
        assert!(LexTool::pattern_for_string("a|b|c") == MatchAny(vec![ MatchAny(vec![ Match(vec!['a']), Match(vec!['b']) ]), Match(vec!['c'])] ));
    }

    #[test]
    fn can_create_grouped_or_match() {
        assert!(LexTool::pattern_for_string("(foo)|(bar)") == MatchAny(vec![ Match(vec!['f', 'o', 'o']), Match(vec!['b', 'a', 'r']) ]));
    }

    #[test]
    fn or_is_processed_early() {
        assert!(LexTool::pattern_for_string("foo|bar") == MatchAll(vec![ Match(vec!['f', 'o']), MatchAny(vec![ Match(vec!['o']), Match(vec!['b']) ]), Match(vec!['a', 'r']) ]));
    }

    #[test]
    fn can_create_simple_grouping() {
        assert!(LexTool::pattern_for_string("(phrase)") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_nested_grouping() {
        assert!(LexTool::pattern_for_string("(p(h(r)a)s)e") == Match(vec!['p', 'h', 'r', 'a', 's', 'e']));
    }

    #[test]
    fn can_create_match_one() {
        assert!(LexTool::pattern_for_string("[a]") == MatchRange('a', 'a'));
    }

    #[test]
    fn can_interpret_newline_quote_characters() {
        assert!(LexTool::pattern_for_string("\\n") == Match(vec![ '\n' ]));
    }

    #[test]
    fn can_create_match_range() {
        assert!(LexTool::pattern_for_string("[a-z]") == MatchRange('a', 'z'));
    }

    #[test]
    fn can_create_match_set() {
        assert!(LexTool::pattern_for_string("[acgh]") == MatchAny(vec![ MatchRange('a', 'a'), MatchRange('c', 'c'), MatchRange('g', 'g'), MatchRange('h', 'h') ]));
    }

    #[test]
    fn can_create_match_multi_range() {
        assert!(LexTool::pattern_for_string("[a-zA-Z]") == MatchAny(vec![ MatchRange('a', 'z'), MatchRange('A', 'Z') ]));
    }

    #[test]
    fn can_create_match_set_and_range() {
        assert!(LexTool::pattern_for_string("[aA-Z]") == MatchAny(vec![ MatchRange('a', 'a'), MatchRange('A', 'Z') ]));
    }

    #[test]
    fn can_generate_simple_lexer() {
        let env     = DynamicEnvironment::new();
        let lexer   = TypedTool::<LexToolInput, ()>::from(Box::new(LexTool::new()));

        let def     = LexToolInput {
            new_tool_name: String::from("sample-lexer"),
            symbols: vec![
                LexToolSymbol { symbol_name: String::from("Hello"), match_rule: String::from("Hello") },
                LexToolSymbol { symbol_name: String::from("Other"), match_rule: String::from("W.*") },
            ]
        };

        lexer.invoke(def, &env);

        let tool                                = env.get_typed_tool("sample-lexer").unwrap();
        let lex_test_result: Vec<LexerMatch>    = tool.invoke("HelloWorld", &env).unwrap();

        assert!(lex_test_result == vec![
            LexerMatch {
                token: String::from("Hello"),
                matched: String::from("Hello"),
                start: 0,
                end: 4
            },

            LexerMatch {
                token: String::from("Other"),
                matched: String::from("World"),
                start: 5,
                end: 9
            }
        ]);
    }
}

<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ptr;
use std::mem;
use mopa;

use glib_ffi;
use gobject_ffi;
use gst_ffi;
use gst_base_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;

use object::*;
use element::*;

pub trait BaseSinkImpl<T: BaseSink>
    : mopa::Any + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static {
    fn start(&self, _element: &T) -> bool {
        true
    }
    fn stop(&self, _element: &T) -> bool {
        true
    }
    fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn;
    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }
    fn event(&self, element: &T, event: &gst::Event) -> bool {
        element.parent_event(event)
    }
}

mopafy_object_impl!(BaseSink, BaseSinkImpl);

pub unsafe trait BaseSink
    : IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType {
    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_event(&self, event: &gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            (*parent_klass)
                .event
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, event.to_glib_none().0))
                })
                .unwrap_or(false)
        }
    }
}

pub unsafe trait BaseSinkClass<T: BaseSink>
where
    T::ImplType: BaseSinkImpl<T>,
{
    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSinkClass);
            klass.start = Some(base_sink_start::<T>);
            klass.stop = Some(base_sink_stop::<T>);
            klass.render = Some(base_sink_render::<T>);
            klass.query = Some(base_sink_query::<T>);
            klass.event = Some(base_sink_event::<T>);
        }
    }
}

glib_wrapper! {
    pub struct RsBaseSink(Object<InstanceStruct<RsBaseSink>>): [gst_base::BaseSink => gst_base_ffi::GstBaseSink,
                                                                gst::Element => gst_ffi::GstElement,
                                                                gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<RsBaseSink>(),
    }
}

unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType> BaseSink for T {}
pub type RsBaseSinkClass = ClassStruct<RsBaseSink>;

// FIXME: Boilerplate
unsafe impl BaseSinkClass<RsBaseSink> for RsBaseSinkClass {}
unsafe impl ElementClass<RsBaseSink> for RsBaseSinkClass {}

#[macro_export]
macro_rules! box_base_sink_impl(
    ($name:ident) => {
        box_element_impl!($name);

        impl<T: BaseSink> BaseSinkImpl<T> for Box<$name<T>> {
            fn start(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.start(element)
            }

            fn stop(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.stop(element)
            }

            fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.render(element, buffer)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.query(element, query)
            }
            fn event(&self, element: &T, event: &gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.event(element, event)
            }
        }
    };
);

box_base_sink_impl!(BaseSinkImpl);

impl ObjectType for RsBaseSink {
    const NAME: &'static str = "RsBaseSink";
    type GlibType = gst_base_ffi::GstBaseSink;
    type GlibClassType = gst_base_ffi::GstBaseSinkClass;
    type ImplType = Box<BaseSinkImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_base_ffi::gst_base_sink_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut RsBaseSinkClass) {
        ElementClass::override_vfuncs(klass, token);
        BaseSinkClass::override_vfuncs(klass, token);
    }

    object_type_fns!();
}

unsafe extern "C" fn base_sink_start<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.start(&wrap) }).to_glib()
}

unsafe extern "C" fn base_sink_stop<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.stop(&wrap) }).to_glib()
}

unsafe extern "C" fn base_sink_render<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let buffer = gst::BufferRef::from_ptr(buffer);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.render(&wrap, buffer)
    }).to_glib()
}

unsafe extern "C" fn base_sink_query<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    query_ptr: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query_ptr);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn base_sink_event<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    event_ptr: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.event(&wrap, &from_glib_none(event_ptr))
    }).to_glib()
}
<commit_msg>Add lots of missing virtual methods to BaseSink<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ptr;
use std::mem;
use mopa;

use glib_ffi;
use gobject_ffi;
use gst_ffi;
use gst_base_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;

use object::*;
use element::*;

pub trait BaseSinkImpl<T: BaseSink>
    : mopa::Any + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static {
    fn start(&self, _element: &T) -> bool {
        true
    }

    fn stop(&self, _element: &T) -> bool {
        true
    }

    fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn;

    fn prepare(&self, _element: &T, _buffer: &gst::BufferRef) -> gst::FlowReturn {
        gst::FlowReturn::Ok
    }

    fn render_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
        for buffer in list.iter() {
            let ret = self.render(element, buffer);
            if ret != gst::FlowReturn::Ok {
                return ret;
            }
        }

        gst::FlowReturn::Ok
    }

    fn prepare_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
        for buffer in list.iter() {
            let ret = self.prepare(element, buffer);
            if ret != gst::FlowReturn::Ok {
                return ret;
            }
        }

        gst::FlowReturn::Ok
    }

    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }

    fn event(&self, element: &T, event: &gst::Event) -> bool {
        element.parent_event(event)
    }

    fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
        element.parent_get_caps(filter)
    }

    fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
        element.parent_set_caps(caps)
    }

    fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
        element.parent_fixate(caps)
    }

    fn unlock(&self, _element: &T) -> bool {
        true
    }

    fn unlock_stop(&self, _element: &T) -> bool {
        true
    }
}

mopafy_object_impl!(BaseSink, BaseSinkImpl);

pub unsafe trait BaseSink
    : IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType {
    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_event(&self, event: &gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            (*parent_klass)
                .event
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, event.to_glib_none().0))
                })
                .unwrap_or(false)
        }
    }

    fn parent_get_caps(&self, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            let filter_ptr = if let Some(filter) = filter {
                filter.as_mut_ptr()
            } else {
                ptr::null_mut()
            };

            (*parent_klass)
                .get_caps
                .map(|f| from_glib_full(f(self.to_glib_none().0, filter_ptr)))
                .unwrap_or(None)
        }
    }

    fn parent_set_caps(&self, caps: &gst::CapsRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
            (*parent_klass)
                .set_caps
                .map(|f| from_glib(f(self.to_glib_none().0, caps.as_mut_ptr())))
                .unwrap_or(true)
        }
    }

    fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;

            match (*parent_klass).fixate {
                Some(fixate) => from_glib_full(fixate(self.to_glib_none().0, caps.into_ptr())),
                None => caps,
            }
        }
    }
}

pub unsafe trait BaseSinkClass<T: BaseSink>
where
    T::ImplType: BaseSinkImpl<T>,
{
    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSinkClass);
            klass.start = Some(base_sink_start::<T>);
            klass.stop = Some(base_sink_stop::<T>);
            klass.render = Some(base_sink_render::<T>);
            klass.render_list = Some(base_sink_render_list::<T>);
            klass.prepare = Some(base_sink_prepare::<T>);
            klass.prepare_list = Some(base_sink_prepare_list::<T>);
            klass.query = Some(base_sink_query::<T>);
            klass.event = Some(base_sink_event::<T>);
            klass.get_caps = Some(base_sink_get_caps::<T>);
            klass.set_caps = Some(base_sink_set_caps::<T>);
            klass.fixate = Some(base_sink_fixate::<T>);
            klass.unlock = Some(base_sink_unlock::<T>);
            klass.unlock_stop = Some(base_sink_unlock_stop::<T>);
        }
    }
}

glib_wrapper! {
    pub struct RsBaseSink(Object<InstanceStruct<RsBaseSink>>): [gst_base::BaseSink => gst_base_ffi::GstBaseSink,
                                                                gst::Element => gst_ffi::GstElement,
                                                                gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<RsBaseSink>(),
    }
}

unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType> BaseSink for T {}
pub type RsBaseSinkClass = ClassStruct<RsBaseSink>;

// FIXME: Boilerplate
unsafe impl BaseSinkClass<RsBaseSink> for RsBaseSinkClass {}
unsafe impl ElementClass<RsBaseSink> for RsBaseSinkClass {}

#[macro_export]
macro_rules! box_base_sink_impl(
    ($name:ident) => {
        box_element_impl!($name);

        impl<T: BaseSink> BaseSinkImpl<T> for Box<$name<T>> {
            fn start(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.start(element)
            }

            fn stop(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.stop(element)
            }

            fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.render(element, buffer)
            }

            fn prepare(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.prepare(element, buffer)
            }

            fn render_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.render_list(element, list)
            }

            fn prepare_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.prepare_list(element, list)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.query(element, query)
            }

            fn event(&self, element: &T, event: &gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.event(element, event)
            }

            fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
                let imp: &$name<T> = self.as_ref();
                imp.get_caps(element, filter)
            }

            fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.set_caps(element, caps)
            }

            fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
                let imp: &$name<T> = self.as_ref();
                imp.fixate(element, caps)
            }

            fn unlock(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.unlock(element)
            }

            fn unlock_stop(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.unlock(element)
            }
        }
    };
);

box_base_sink_impl!(BaseSinkImpl);

impl ObjectType for RsBaseSink {
    const NAME: &'static str = "RsBaseSink";
    type GlibType = gst_base_ffi::GstBaseSink;
    type GlibClassType = gst_base_ffi::GstBaseSinkClass;
    type ImplType = Box<BaseSinkImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_base_ffi::gst_base_sink_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut RsBaseSinkClass) {
        ElementClass::override_vfuncs(klass, token);
        BaseSinkClass::override_vfuncs(klass, token);
    }

    object_type_fns!();
}

unsafe extern "C" fn base_sink_start<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.start(&wrap) }).to_glib()
}

unsafe extern "C" fn base_sink_stop<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.stop(&wrap) }).to_glib()
}

unsafe extern "C" fn base_sink_render<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let buffer = gst::BufferRef::from_ptr(buffer);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.render(&wrap, buffer)
    }).to_glib()
}

unsafe extern "C" fn base_sink_prepare<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let buffer = gst::BufferRef::from_ptr(buffer);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.prepare(&wrap, buffer)
    }).to_glib()
}

unsafe extern "C" fn base_sink_render_list<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    list: *mut gst_ffi::GstBufferList,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let list = gst::BufferListRef::from_ptr(list);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.render_list(&wrap, list)
    }).to_glib()
}

unsafe extern "C" fn base_sink_prepare_list<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    list: *mut gst_ffi::GstBufferList,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let list = gst::BufferListRef::from_ptr(list);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.prepare_list(&wrap, list)
    }).to_glib()
}

unsafe extern "C" fn base_sink_query<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    query_ptr: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query_ptr);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn base_sink_event<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    event_ptr: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.event(&wrap, &from_glib_none(event_ptr))
    }).to_glib()
}

unsafe extern "C" fn base_sink_get_caps<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    filter: *mut gst_ffi::GstCaps,
) -> *mut gst_ffi::GstCaps
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let filter = if filter.is_null() {
        None
    } else {
        Some(gst::CapsRef::from_ptr(filter))
    };

    panic_to_error!(
        &wrap,
        &element.panicked,
        None,
        { imp.get_caps(&wrap, filter) }
    ).map(|caps| caps.into_ptr())
        .unwrap_or(ptr::null_mut())
}

unsafe extern "C" fn base_sink_set_caps<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    caps: *mut gst_ffi::GstCaps,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let caps = gst::CapsRef::from_ptr(caps);

    panic_to_error!(
        &wrap,
        &element.panicked,
        false,
        { imp.set_caps(&wrap, caps) }
    ).to_glib()
}

unsafe extern "C" fn base_sink_fixate<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
    caps: *mut gst_ffi::GstCaps,
) -> *mut gst_ffi::GstCaps
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let caps = from_glib_full(caps);

    panic_to_error!(&wrap, &element.panicked, gst::Caps::new_empty(), {
        imp.fixate(&wrap, caps)
    }).into_ptr()
}

unsafe extern "C" fn base_sink_unlock<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.unlock(&wrap) }).to_glib()
}

unsafe extern "C" fn base_sink_unlock_stop<T: BaseSink>(
    ptr: *mut gst_base_ffi::GstBaseSink,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSinkImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.unlock_stop(&wrap) }).to_glib()
}
<|endoftext|>


<commit_before>use std::fmt;
use common::IntToEnumError;

#[derive(Debug,PartialEq)]
#[repr(u8)]
pub enum TlsAlertSeverity {
    Warning = 0x01,
    Fatal   = 0x02,
}

#[derive(Debug,PartialEq)]
#[repr(u8)]
pub enum TlsAlertDescription {
    CloseNotify            = 0x00,
    UnexpectedMessage      = 0x0A,
    BadRecordMac           = 0x14,
    DecryptionFailed       = 0x15,
    RecordOverflow         = 0x16,
    DecompressionFailure   = 0x1E,
    HandshakeFailure       = 0x28,
    NoCertificate          = 0x29,
    BadCertificate         = 0x2A,
    UnsupportedCertificate = 0x2B,
    CertificateRevoked     = 0x2C,
    CertificateExpired     = 0x2D,
    CertificateUnknown     = 0x2E,
    IllegalParameter       = 0x2F,
    UnknownCa              = 0x30,
    AccessDenied           = 0x31,
    DecodeError            = 0x32,
    DecryptError           = 0x33,
    ExportRestriction      = 0x3C,
    ProtocolVersion        = 0x46,
    InsufficientSecurity   = 0x47,
    InternalError          = 0x50,
    UserCancelled          = 0x5A,
    NoRenegotiation        = 0x64,
}

#[derive(Clone,PartialEq)]
pub struct TlsMessageAlert {
    pub severity: u8,
    pub code: u8,
}

impl fmt::Display for TlsMessageAlert {
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        // // XXX that does not always work, since Alert can be encrypted
        // let s : TlsAlertSeverity = self.severity.into();
        // let d : TlsAlertDescription = self.code.into();
        // write!(out, "TlsAlert(severity={:?},code={:?})", s, d)
        write!(out, "TlsAlert(severity={:x},code=0x{:x})", self.severity, self.code)
    }
}

impl fmt::Debug for TlsMessageAlert {
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self,out)
    }
}

impl TlsAlertSeverity {
    pub fn try_from_u8(original: u8) -> Result<Self, IntToEnumError> {
        match original {
            0x01 => Ok(TlsAlertSeverity::Warning),
            0x02 => Ok(TlsAlertSeverity::Fatal),
            n => Err(IntToEnumError::InvalidU8(n)),
        }
    }
}

impl From<u8> for TlsAlertSeverity {
    fn from(t:u8) -> TlsAlertSeverity {
        // assert!(TlsAlertSeverity::Warning as u8 <= t && t <= TlsAlertSeverity::Fatal as u8);
        // unsafe { transmute(t) }
        match TlsAlertSeverity::try_from_u8(t) {
            Ok(s)  => s,
            Err(_) => panic!("Invalid TlsAlertSeverity {}",t),
        }
    }
}

impl TlsAlertDescription {
    pub fn try_from_u8(original: u8) -> Result<Self, IntToEnumError> {
        match original {
            0x00 => Ok(TlsAlertDescription::CloseNotify),
            0x0A => Ok(TlsAlertDescription::UnexpectedMessage),
            0x14 => Ok(TlsAlertDescription::BadRecordMac),
            0x15 => Ok(TlsAlertDescription::DecryptionFailed),
            0x16 => Ok(TlsAlertDescription::RecordOverflow),
            0x1E => Ok(TlsAlertDescription::DecompressionFailure),
            0x28 => Ok(TlsAlertDescription::HandshakeFailure),
            0x29 => Ok(TlsAlertDescription::NoCertificate),
            0x2A => Ok(TlsAlertDescription::BadCertificate),
            0x2B => Ok(TlsAlertDescription::UnsupportedCertificate),
            0x2C => Ok(TlsAlertDescription::CertificateRevoked),
            0x2D => Ok(TlsAlertDescription::CertificateExpired),
            0x2E => Ok(TlsAlertDescription::CertificateUnknown),
            0x2F => Ok(TlsAlertDescription::IllegalParameter),
            0x30 => Ok(TlsAlertDescription::UnknownCa),
            0x31 => Ok(TlsAlertDescription::AccessDenied),
            0x32 => Ok(TlsAlertDescription::DecodeError),
            0x33 => Ok(TlsAlertDescription::DecryptError),
            0x3C => Ok(TlsAlertDescription::ExportRestriction),
            0x46 => Ok(TlsAlertDescription::ProtocolVersion),
            0x47 => Ok(TlsAlertDescription::InsufficientSecurity),
            0x50 => Ok(TlsAlertDescription::InternalError),
            0x5A => Ok(TlsAlertDescription::UserCancelled),
            0x64 => Ok(TlsAlertDescription::NoRenegotiation),
            n => Err(IntToEnumError::InvalidU8(n)),
        }
    }
}

impl From<u8> for TlsAlertDescription {
    fn from(t:u8) -> TlsAlertDescription {
        match TlsAlertDescription::try_from_u8(t) {
            Ok(s)  => s,
            Err(_) => panic!("Invalid TlsAlertDescription {}",t),
        }
    }
}

#[cfg(test)]
mod tests {
    use tls_alert::*;

#[test]
fn test_tlsalert_cast_severity() {
    let a = TlsAlertSeverity::Warning;

    let a_u8 = a as u8;
    assert_eq!(a_u8, 0x01);

    let b : TlsAlertSeverity = a_u8.into();
    assert_eq!(b, TlsAlertSeverity::Warning);
}

#[test]
fn test_tlsalert_cast_description() {
    let a = TlsAlertDescription::HandshakeFailure;

    let a_u8 = a as u8;
    assert_eq!(a_u8, 0x28);

    let b : TlsAlertDescription = a_u8.into();
    assert_eq!(b, TlsAlertDescription::HandshakeFailure);
}

} // mod tests
<commit_msg>Add TlsAlert InappropriateFallback<commit_after>use std::fmt;
use common::IntToEnumError;

#[derive(Debug,PartialEq)]
#[repr(u8)]
pub enum TlsAlertSeverity {
    Warning = 0x01,
    Fatal   = 0x02,
}

#[derive(Debug,PartialEq)]
#[repr(u8)]
pub enum TlsAlertDescription {
    CloseNotify            = 0x00,
    UnexpectedMessage      = 0x0A,
    BadRecordMac           = 0x14,
    DecryptionFailed       = 0x15,
    RecordOverflow         = 0x16,
    DecompressionFailure   = 0x1E,
    HandshakeFailure       = 0x28,
    NoCertificate          = 0x29,
    BadCertificate         = 0x2A,
    UnsupportedCertificate = 0x2B,
    CertificateRevoked     = 0x2C,
    CertificateExpired     = 0x2D,
    CertificateUnknown     = 0x2E,
    IllegalParameter       = 0x2F,
    UnknownCa              = 0x30,
    AccessDenied           = 0x31,
    DecodeError            = 0x32,
    DecryptError           = 0x33,
    ExportRestriction      = 0x3C,
    ProtocolVersion        = 0x46,
    InsufficientSecurity   = 0x47,
    InternalError          = 0x50,
    InappropriateFallback  = 0x56,
    UserCancelled          = 0x5A,
    NoRenegotiation        = 0x64,
}

#[derive(Clone,PartialEq)]
pub struct TlsMessageAlert {
    pub severity: u8,
    pub code: u8,
}

impl fmt::Display for TlsMessageAlert {
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        // // XXX that does not always work, since Alert can be encrypted
        // let s : TlsAlertSeverity = self.severity.into();
        // let d : TlsAlertDescription = self.code.into();
        // write!(out, "TlsAlert(severity={:?},code={:?})", s, d)
        write!(out, "TlsAlert(severity={:x},code=0x{:x})", self.severity, self.code)
    }
}

impl fmt::Debug for TlsMessageAlert {
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self,out)
    }
}

impl TlsAlertSeverity {
    pub fn try_from_u8(original: u8) -> Result<Self, IntToEnumError> {
        match original {
            0x01 => Ok(TlsAlertSeverity::Warning),
            0x02 => Ok(TlsAlertSeverity::Fatal),
            n => Err(IntToEnumError::InvalidU8(n)),
        }
    }
}

impl From<u8> for TlsAlertSeverity {
    fn from(t:u8) -> TlsAlertSeverity {
        // assert!(TlsAlertSeverity::Warning as u8 <= t && t <= TlsAlertSeverity::Fatal as u8);
        // unsafe { transmute(t) }
        match TlsAlertSeverity::try_from_u8(t) {
            Ok(s)  => s,
            Err(_) => panic!("Invalid TlsAlertSeverity {}",t),
        }
    }
}

impl TlsAlertDescription {
    pub fn try_from_u8(original: u8) -> Result<Self, IntToEnumError> {
        match original {
            0x00 => Ok(TlsAlertDescription::CloseNotify),
            0x0A => Ok(TlsAlertDescription::UnexpectedMessage),
            0x14 => Ok(TlsAlertDescription::BadRecordMac),
            0x15 => Ok(TlsAlertDescription::DecryptionFailed),
            0x16 => Ok(TlsAlertDescription::RecordOverflow),
            0x1E => Ok(TlsAlertDescription::DecompressionFailure),
            0x28 => Ok(TlsAlertDescription::HandshakeFailure),
            0x29 => Ok(TlsAlertDescription::NoCertificate),
            0x2A => Ok(TlsAlertDescription::BadCertificate),
            0x2B => Ok(TlsAlertDescription::UnsupportedCertificate),
            0x2C => Ok(TlsAlertDescription::CertificateRevoked),
            0x2D => Ok(TlsAlertDescription::CertificateExpired),
            0x2E => Ok(TlsAlertDescription::CertificateUnknown),
            0x2F => Ok(TlsAlertDescription::IllegalParameter),
            0x30 => Ok(TlsAlertDescription::UnknownCa),
            0x31 => Ok(TlsAlertDescription::AccessDenied),
            0x32 => Ok(TlsAlertDescription::DecodeError),
            0x33 => Ok(TlsAlertDescription::DecryptError),
            0x3C => Ok(TlsAlertDescription::ExportRestriction),
            0x46 => Ok(TlsAlertDescription::ProtocolVersion),
            0x47 => Ok(TlsAlertDescription::InsufficientSecurity),
            0x50 => Ok(TlsAlertDescription::InternalError),
            0x5A => Ok(TlsAlertDescription::UserCancelled),
            0x64 => Ok(TlsAlertDescription::NoRenegotiation),
            n => Err(IntToEnumError::InvalidU8(n)),
        }
    }
}

impl From<u8> for TlsAlertDescription {
    fn from(t:u8) -> TlsAlertDescription {
        match TlsAlertDescription::try_from_u8(t) {
            Ok(s)  => s,
            Err(_) => panic!("Invalid TlsAlertDescription {}",t),
        }
    }
}

#[cfg(test)]
mod tests {
    use tls_alert::*;

#[test]
fn test_tlsalert_cast_severity() {
    let a = TlsAlertSeverity::Warning;

    let a_u8 = a as u8;
    assert_eq!(a_u8, 0x01);

    let b : TlsAlertSeverity = a_u8.into();
    assert_eq!(b, TlsAlertSeverity::Warning);
}

#[test]
fn test_tlsalert_cast_description() {
    let a = TlsAlertDescription::HandshakeFailure;

    let a_u8 = a as u8;
    assert_eq!(a_u8, 0x28);

    let b : TlsAlertDescription = a_u8.into();
    assert_eq!(b, TlsAlertDescription::HandshakeFailure);
}

} // mod tests
<|endoftext|>