<commit_before>//!A raytracer.
#![feature(path, io)]
extern crate image;
extern crate rand;

use std::old_io::File;
use std::num::Float;
use std::f32::consts::PI_2;

use rand::distributions::IndependentSample;
use rand::Rng;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection<ObjectId> {
    time: f32,
    point: Point3,
    normal: Vec3,
    object: ObjectId
}

trait Scene {
    // TODO: Should this have a "not present" id?
    type ObjectId: Copy;

    fn intersect(&self, ray: Ray3, previous: Option<Self::ObjectId>) -> Option<Intersection<Self::ObjectId>>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    type ObjectId = ();
    fn intersect(&self, ray: Ray3, previous: Option<()>) -> Option<Intersection<()>> {
        if let Some(()) = previous {
            return None;
        }

        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > 0. {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal,
                    object: ()
                })
            } else if t2 > 0. {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal,
                    object: ()
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    type ObjectId = ();
    fn intersect(&self, ray: Ray3, previous: Option<()>) -> Option<Intersection<()>> {
        if let Some(()) = previous {
            return None;
        }

        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > 0. {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal,
                    object: ()
                })
            } else {
                None
            }
        }
    }
}

#[derive(Copy)]
enum Choice<A, B> {
    OptA(A),
    OptB(B)
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    type ObjectId = Choice<A::ObjectId, B::ObjectId>;
    fn intersect(&self, ray: Ray3, previous: Option<Choice<A::ObjectId, B::ObjectId>>) -> Option<Intersection<Choice<A::ObjectId, B::ObjectId>>> {
        let (aid, bid) = match previous {
            None => (None, None),
            Some(Choice::OptA(aid)) => (Some(aid), None),
            Some(Choice::OptB(bid)) => (None, Some(bid))
        };

        match self.0.intersect(ray, aid) {
            Some(ai) => {
                match self.1.intersect(ray, bid) {
                    Some(bi) => if ai.time < bi.time {
                        Some(Intersection {
                            time: ai.time,
                            normal: ai.normal,
                            point: ai.point,
                            object: Choice::OptA(ai.object)
                        })
                    } else {
                        Some(Intersection {
                            time: bi.time,
                            normal: bi.normal,
                            point: bi.point,
                            object: Choice::OptB(bi.object)
                        })
                    },
                    None => Some(Intersection {
                        time: ai.time,
                        normal: ai.normal,
                        point: ai.point,
                        object: Choice::OptA(ai.object)
                    })
                }
            },
            None => match self.1.intersect(ray, bid) {
                Some(bi) => Some(Intersection {
                    time: bi.time,
                    normal: bi.normal,
                    point: bi.point,
                    object: Choice::OptB(bi.object)
                }),
                None => None
            }
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn rand_sphere<R: rand::Rng>(rng: &mut R) -> Vec3 {
    let z = rand::distributions::Range::new(-1., 1.).ind_sample(rng);
    let r = (1. - z*z).sqrt();
    let angle = rand::distributions::Range::new(0., PI_2).ind_sample(rng);
    Vec3::new(r*angle.cos(), r*angle.sin(), z)
}

fn main() {
    let mut rng = rand::thread_rng();

    let rays_per_pixel = 50;
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        ((Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        }),
        (Plane {
            origin: Point3::new(0.0, 2.0, 0.0),
            normal: Vec3::new(0.0, -1.0, 0.0)
        },
        Plane {
            origin: Point3::new(0.0, -3.0, 0.0),
            normal: Vec3::new(0.0, 1.0, 0.0)
        }))
    );
    let light = Point3::new(1.0, -1.5, 0.5);

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let mut total_light = 0.;
        for _ in 0..rays_per_pixel {
            let mut ray = Ray3 {
                start: Point3::new(0., 0., -8.0),
                dir: Vec3::new(cx, cy, 8.0)
            };
            let mut prev_object = None;
            loop {
                if let Some(intersection) = scene.intersect(ray, prev_object) {
                    prev_object = Some(intersection.object);

                    let light_ray = Ray3 {
                        start: intersection.point,
                        dir: light - intersection.point
                    };

                    let can_see_light = match scene.intersect(light_ray, prev_object) {
                        Some(light_intersection) => {
                            light_intersection.time > 1.
                        },
                        None => true
                    };

                    if can_see_light {
                        let light_strength = 10.0 / light_ray.dir.mag2();
                        let scale = (intersection.normal.mag2() * light_ray.dir.mag2()).sqrt();
                        total_light += light_strength * intersection.normal.dot(light_ray.dir) / scale;
                    }

                    let cand_dir = rand_sphere(&mut rng);
                    let dir = if cand_dir.dot(intersection.normal) < 0. {
                        -cand_dir
                    } else {
                        cand_dir
                    };
                    ray = Ray3 {
                        start: intersection.point,
                        dir: dir
                    };

                    if rng.next_f32() > dir.dot(intersection.normal) / intersection.normal.mag2().sqrt() {
                        break;
                    }
                } else {
                    break;
                }
            }
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(clamp(total_light / rays_per_pixel as f32)*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<commit_msg>Use emissive materials instead of a single point light. This is much slower.<commit_after>//!A raytracer.
#![feature(path, io)]
extern crate image;
extern crate rand;

use std::old_io::File;
use std::num::Float;
use std::f32::consts::PI_2;

use rand::distributions::IndependentSample;
use rand::Rng;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection<ObjectId> {
    time: f32,
    point: Point3,
    normal: Vec3,
    emitted: f32,
    object: ObjectId
}

trait Scene {
    // TODO: Should this have a "not present" id?
    type ObjectId: Copy;

    fn intersect(&self, ray: Ray3, previous: Option<Self::ObjectId>) -> Option<Intersection<Self::ObjectId>>;
}

struct Material {
    emitted_radiance: f32
}

struct Sphere {
    center: Point3,
    radius: f32,
    material: Material
}

impl Scene for Sphere {
    type ObjectId = ();
    fn intersect(&self, ray: Ray3, previous: Option<()>) -> Option<Intersection<()>> {
        if let Some(()) = previous {
            return None;
        }

        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > 0. {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal,
                    emitted: self.material.emitted_radiance,
                    object: ()
                })
            } else if t2 > 0. {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal,
                    emitted: self.material.emitted_radiance,
                    object: ()
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3,
    material: Material
}

impl Scene for Plane {
    type ObjectId = ();
    fn intersect(&self, ray: Ray3, previous: Option<()>) -> Option<Intersection<()>> {
        if let Some(()) = previous {
            return None;
        }

        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > 0. {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal,
                    emitted: self.material.emitted_radiance,
                    object: ()
                })
            } else {
                None
            }
        }
    }
}

#[derive(Copy)]
enum Choice<A, B> {
    OptA(A),
    OptB(B)
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    type ObjectId = Choice<A::ObjectId, B::ObjectId>;
    fn intersect(&self, ray: Ray3, previous: Option<Choice<A::ObjectId, B::ObjectId>>) -> Option<Intersection<Choice<A::ObjectId, B::ObjectId>>> {
        let (aid, bid) = match previous {
            None => (None, None),
            Some(Choice::OptA(aid)) => (Some(aid), None),
            Some(Choice::OptB(bid)) => (None, Some(bid))
        };

        match self.0.intersect(ray, aid) {
            Some(ai) => {
                match self.1.intersect(ray, bid) {
                    Some(bi) => if ai.time < bi.time {
                        Some(Intersection {
                            time: ai.time,
                            normal: ai.normal,
                            point: ai.point,
                            emitted: ai.emitted,
                            object: Choice::OptA(ai.object)
                        })
                    } else {
                        Some(Intersection {
                            time: bi.time,
                            normal: bi.normal,
                            point: bi.point,
                            emitted: bi.emitted,
                            object: Choice::OptB(bi.object)
                        })
                    },
                    None => Some(Intersection {
                        time: ai.time,
                        normal: ai.normal,
                        point: ai.point,
                        emitted: ai.emitted,
                        object: Choice::OptA(ai.object)
                    })
                }
            },
            None => match self.1.intersect(ray, bid) {
                Some(bi) => Some(Intersection {
                    time: bi.time,
                    normal: bi.normal,
                    point: bi.point,
                    emitted: bi.emitted,
                    object: Choice::OptB(bi.object)
                }),
                None => None
            }
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn rand_sphere<R: rand::Rng>(rng: &mut R) -> Vec3 {
    let z = rand::distributions::Range::new(-1., 1.).ind_sample(rng);
    let r = (1. - z*z).sqrt();
    let angle = rand::distributions::Range::new(0., PI_2).ind_sample(rng);
    Vec3::new(r*angle.cos(), r*angle.sin(), z)
}

fn main() {
    let mut rng = rand::thread_rng();

    let rays_per_pixel = 100;
    let scene = (
        ((Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3,
            material: Material { emitted_radiance: 0. }
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35,
            material: Material { emitted_radiance: 0. }
        }),
        Sphere {
            center: Point3::new(1.0, 2.5, 0.5),
            radius: 1.0,
            material: Material { emitted_radiance: 20. }
        }),
        ((Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0),
            material: Material { emitted_radiance: 0. }
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0),
            material: Material { emitted_radiance: 0. }
        }),
        (Plane {
            origin: Point3::new(0.0, 2.0, 0.0),
            normal: Vec3::new(0.0, -1.0, 0.0),
            material: Material { emitted_radiance: 0. }
        },
        Plane {
            origin: Point3::new(0.0, -3.0, 0.0),
            normal: Vec3::new(0.0, 1.0, 0.0),
            material: Material { emitted_radiance: 0. }
        }))
    );

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let mut total_light = 0.;
        for _ in 0..rays_per_pixel {
            let mut ray = Ray3 {
                start: Point3::new(0., 0., -8.0),
                dir: Vec3::new(cx, cy, 8.0)
            };
            let mut prev_object = None;
            let mut scale = 1.;
            loop {
                if let Some(intersection) = scene.intersect(ray, prev_object) {
                    prev_object = Some(intersection.object);

                    total_light += scale * intersection.emitted;

                    let cand_dir = rand_sphere(&mut rng);
                    let dir = if cand_dir.dot(intersection.normal) < 0. {
                        -cand_dir
                    } else {
                        cand_dir
                    };
                    ray = Ray3 {
                        start: intersection.point,
                        dir: dir
                    };

                    let p = dir.dot(intersection.normal) / intersection.normal.mag2().sqrt();
                    if scale > 0.2 {
                        scale *= p;
                    } else if rng.next_f32() > p {
                        break;
                    }
                } else {
                    break;
                }
            }
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(clamp(total_light / rays_per_pixel as f32)*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<|endoftext|>


<commit_before><commit_msg>Use more FloatCore in src/sign.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Size: reorder and group operator impls<commit_after><|endoftext|>


<commit_before>
use std::fmt::Debug;
use std::io;
use std::io::Cursor;
use std::time::Duration;

use super::*;
use codec::*;

const BUFFER_STR: &'static str = "hello world";

fn writer() -> Cursor<Vec<u8>> {
    Cursor::new(Vec::new())
}

fn body() -> Vec<u8> {
    BUFFER_STR.to_owned().into_bytes()
}

fn check<T, F1, F2>(buf: Vec<u8>, decode: &F1, expected: T, encode: &F2) -> ()
    where F1: Fn(Cursor<Vec<u8>>) -> io::Result<T>,
          F2: Fn(&mut Cursor<Vec<u8>>, &T) -> io::Result<()>,
          T: PartialEq + Debug
{
    let msg = decode(Cursor::new(buf.clone())).unwrap();
    assert_eq!(msg, expected);

    let mut w = writer();
    encode(&mut w, &expected).unwrap();

    assert_eq!(w.into_inner(), buf);
}

#[test]
fn test_treq() {
    // Request type: Treq(1,None,BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Treq { headers: Vec::new(), body: body() };
    check(buf, &decode_treq, expected, &encode_treq);
}

#[test]
fn test_rreqok() {
    // Request type: RreqOk(1,BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rmsg::Ok(body());
    check(buf, &decode_rreq, expected, &encode_rreq);
}

#[test]
fn test_rreqerror() {
    // Request type: RreqError(1,hello world)
    let buf = vec![0x01, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rmsg::Error(BUFFER_STR.to_owned());
    check(buf, &decode_rreq, expected, &encode_rreq);
}

#[test]
fn test_rreqnack() {
    // Request type: RreqNack(1)
    let buf = vec![0x02, ];

    let expected = Rmsg::Nack("".to_owned());
    check(buf, &decode_rreq, expected, &encode_rreq);
}

#[test]
fn test_tdispatch_1() {
    // Request type: Tdispatch(1,List(),Path(path),Dtab(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x05, 0x2f, 0x70, 0x61, 0x74,
               0x68, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Tdispatch {
        contexts: Vec::new(),
        dest: "/path".to_owned(),
        dtab: Dtab::new(),
        body: body(),
    };

    check(buf, &decode_tdispatch, expected, &encode_tdispatch);
}

#[test]
fn test_tdispatch_2() {
    // Request type: Tdispatch(1,List((BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))),Path(path),Dtab(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x01, 0x00, 0x0b, 0x68, 0x65, 0x6c, 0x6c,
               0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00,
               0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, 0x00, 0x05, 0x2f, 0x70,
               0x61, 0x74, 0x68, 0x00, 0x00, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               ];

    let msg = decode_tdispatch(buf.as_slice()).unwrap();
    let expected = Tdispatch {
        contexts: vec![(body(), body())],
        dest: "/path".to_owned(),
        dtab: Dtab::new(),
        body: body(),
    };

    assert_eq!(msg, expected);

    let mut w = writer();
    encode_tdispatch(&mut w, &expected).unwrap();

    assert_eq!(w.into_inner(), buf);
    check(buf, &decode_tdispatch, expected, &encode_tdispatch);
}

#[test]
fn test_tdispatch_3() {
    // Request type: Tdispatch(1,List(),Path(path),Dtab(/f/foo=>/go),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x05, 0x2f, 0x70, 0x61, 0x74,
               0x68, 0x00, 0x01, 0x00, 0x06, 0x2f, 0x66, 0x2f,
               0x66, 0x6f, 0x6f, 0x00, 0x03, 0x2f, 0x67, 0x6f,
               0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
               0x72, 0x6c, 0x64, ];

    let dtab = Dtab::from_entries(
        vec![Dentry::new("/f/foo".to_owned(), "/go".to_owned())]
    );

    let expected = Tdispatch {
        contexts: vec![],
        dest: "/path".to_owned(),
        dtab: dtab,
        body: body(),
    };

    check(buf, &decode_tdispatch, expected, &encode_tdispatch);
}

#[test]
fn test_rdispatchok_1() {
    // Request type: RdispatchOk(1,List(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Ok(body()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch);
}

#[test]
fn test_rdispatchok_2() {
    // Request type: RdispatchOk(1,List((BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x01, 0x00, 0x0b, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               0x00, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
               0x77, 0x6f, 0x72, 0x6c, 0x64, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               ];

    let expected = Rdispatch {
        contexts: vec![(body(), body())],
        msg: Rmsg::Ok(body()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch);
}

#[test]
fn test_rdispatcherror() {
    // Request type: RdispatchError(1,List(),hello world)
    let buf = vec![0x01, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Error(BUFFER_STR.to_owned()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch);
}

#[test]
fn test_rdispatchnack() {
    // Request type: RdispatchNack(1,List())
    let buf = vec![0x02, 0x00, 0x00, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Nack("".to_owned()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch);
}

#[test]
fn test_rerr() {
    // Request type: Rerr(1,hello world)
    let buf = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
               0x72, 0x6c, 0x64, ];

    let msg = decode_rerr(buf.as_slice()).unwrap();
    let expected = BUFFER_STR.to_owned();

    assert_eq!(msg, expected);

    let mut w = writer();
    encode_rerr(&mut w, &expected).unwrap();

    assert_eq!(w.into_inner(), buf);
}

#[test]
fn test_tdiscarded() {
    // Request type: Tdiscarded(1,hello world)
    let buf = vec![0x00, 0x00, 0x01, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Tdiscarded {
        id: 1,
        msg: BUFFER_STR.to_owned(),
    };

    check(buf, &decode_tdiscarded, expected, &encode_tdiscarded);
}

#[test]
fn test_tlease() {
    // Request type: Tlease(0,1000)
    let buf = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, ];

    let expected = Duration::from_millis(1000);

    check(buf, &decode_tlease_duration, expected, &encode_tlease_duration);
}
<commit_msg>conformance now checks frame sizes<commit_after>
use std::fmt::Debug;
use std::io;
use std::io::Cursor;
use std::time::Duration;

use super::*;
use codec::*;
use codec::size::*;

const BUFFER_STR: &'static str = "hello world";

fn writer() -> Cursor<Vec<u8>> {
    Cursor::new(Vec::new())
}

fn body() -> Vec<u8> {
    BUFFER_STR.to_owned().into_bytes()
}

fn check<T, F1, F2, F3>(buf: Vec<u8>, decode: &F1, expected: T, encode: &F2, size: F3) -> ()
    where F1: Fn(Cursor<Vec<u8>>) -> io::Result<T>,
          F2: Fn(&mut Cursor<Vec<u8>>, &T) -> io::Result<()>,
          F3: FnOnce(T) -> MessageFrame,
          T: PartialEq + Debug
{
    let msg = decode(Cursor::new(buf.clone())).unwrap();
    assert_eq!(msg, expected);

    let mut w = writer();
    encode(&mut w, &expected).unwrap();

    assert_eq!(frame_size(&size(expected)), buf.len());
    assert_eq!(w.into_inner(), buf);
}

#[test]
fn test_treq() {
    // Request type: Treq(1,None,BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Treq { headers: Vec::new(), body: body() };
    check(buf, &decode_treq, expected, &encode_treq, |t| { MessageFrame::Treq(t)});
}

#[test]
fn test_rreqok() {
    // Request type: RreqOk(1,BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rmsg::Ok(body());
    check(buf, &decode_rreq, expected, &encode_rreq, |t| { MessageFrame::Rreq(t) });
}

#[test]
fn test_rreqerror() {
    // Request type: RreqError(1,hello world)
    let buf = vec![0x01, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rmsg::Error(BUFFER_STR.to_owned());
    check(buf, &decode_rreq, expected, &encode_rreq, |t| MessageFrame::Rreq(t));
}

#[test]
fn test_rreqnack() {
    // Request type: RreqNack(1)
    let buf = vec![0x02, ];

    let expected = Rmsg::Nack("".to_owned());
    check(buf, &decode_rreq, expected, &encode_rreq, |t| { MessageFrame::Rreq(t) });
}

#[test]
fn test_tdispatch_1() {
    // Request type: Tdispatch(1,List(),Path(path),Dtab(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x05, 0x2f, 0x70, 0x61, 0x74,
               0x68, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Tdispatch {
        contexts: Vec::new(),
        dest: "/path".to_owned(),
        dtab: Dtab::new(),
        body: body(),
    };

    check(buf, &decode_tdispatch, expected, &encode_tdispatch, |t| MessageFrame::Tdispatch(t) );
}

#[test]
fn test_tdispatch_2() {
    // Request type: Tdispatch(1,List((BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))),Path(path),Dtab(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x01, 0x00, 0x0b, 0x68, 0x65, 0x6c, 0x6c,
               0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00,
               0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77,
               0x6f, 0x72, 0x6c, 0x64, 0x00, 0x05, 0x2f, 0x70,
               0x61, 0x74, 0x68, 0x00, 0x00, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               ];

    let msg = decode_tdispatch(buf.as_slice()).unwrap();
    let expected = Tdispatch {
        contexts: vec![(body(), body())],
        dest: "/path".to_owned(),
        dtab: Dtab::new(),
        body: body(),
    };

    assert_eq!(msg, expected);

    let mut w = writer();
    encode_tdispatch(&mut w, &expected).unwrap();

    assert_eq!(w.into_inner(), buf);
    check(buf, &decode_tdispatch, expected, &encode_tdispatch, |t| MessageFrame::Tdispatch(t) );
}

#[test]
fn test_tdispatch_3() {
    // Request type: Tdispatch(1,List(),Path(path),Dtab(/f/foo=>/go),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x05, 0x2f, 0x70, 0x61, 0x74,
               0x68, 0x00, 0x01, 0x00, 0x06, 0x2f, 0x66, 0x2f,
               0x66, 0x6f, 0x6f, 0x00, 0x03, 0x2f, 0x67, 0x6f,
               0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
               0x72, 0x6c, 0x64, ];

    let dtab = Dtab::from_entries(
        vec![Dentry::new("/f/foo".to_owned(), "/go".to_owned())]
    );

    let expected = Tdispatch {
        contexts: vec![],
        dest: "/path".to_owned(),
        dtab: dtab,
        body: body(),
    };

    check(buf, &decode_tdispatch, expected, &encode_tdispatch, |t| MessageFrame::Tdispatch(t) );
}

#[test]
fn test_rdispatchok_1() {
    // Request type: RdispatchOk(1,List(),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Ok(body()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch, |t| MessageFrame::Rdispatch(t) );
}

#[test]
fn test_rdispatchok_2() {
    // Request type: RdispatchOk(1,List((BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))),BigEndianHeapChannelBuffer(ridx=0, widx=11, cap=11))
    let buf = vec![0x00, 0x00, 0x01, 0x00, 0x0b, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               0x00, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
               0x77, 0x6f, 0x72, 0x6c, 0x64, 0x68, 0x65, 0x6c,
               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
               ];

    let expected = Rdispatch {
        contexts: vec![(body(), body())],
        msg: Rmsg::Ok(body()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch, |t| MessageFrame::Rdispatch(t) );
}

#[test]
fn test_rdispatcherror() {
    // Request type: RdispatchError(1,List(),hello world)
    let buf = vec![0x01, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Error(BUFFER_STR.to_owned()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch, |t| MessageFrame::Rdispatch(t) );
}

#[test]
fn test_rdispatchnack() {
    // Request type: RdispatchNack(1,List())
    let buf = vec![0x02, 0x00, 0x00, ];

    let expected = Rdispatch {
        contexts: vec![],
        msg: Rmsg::Nack("".to_owned()),
    };

    check(buf, &decode_rdispatch, expected, &encode_rdispatch, |t| MessageFrame::Rdispatch(t) );
}

#[test]
fn test_rerr() {
    // Request type: Rerr(1,hello world)
    let buf = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
               0x72, 0x6c, 0x64, ];

    let msg = decode_rerr(buf.as_slice()).unwrap();
    let expected = BUFFER_STR.to_owned();

    assert_eq!(msg, expected);

    let mut w = writer();
    encode_rerr(&mut w, &expected).unwrap();

    assert_eq!(w.into_inner(), buf);
}

#[test]
fn test_tdiscarded() {
    // Request type: Tdiscarded(1,hello world)
    let buf = vec![0x00, 0x00, 0x01, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
               0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ];

    let expected = Tdiscarded {
        id: 1,
        msg: BUFFER_STR.to_owned(),
    };

    check(buf, &decode_tdiscarded, expected, &encode_tdiscarded, |t| MessageFrame::Tdiscarded(t));
}

#[test]
fn test_tlease() {
    // Request type: Tlease(0,1000)
    let buf = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, ];

    let expected = Duration::from_millis(1000);

    check(buf, &decode_tlease_duration, expected, &encode_tlease_duration, |t| MessageFrame::Tlease(t));
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::str::FromStr;

use header::{Header, Raw};
use header::parsing::{from_one_raw_str};

/// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1)
///
/// The "Range" header field on a GET request modifies the method
/// semantics to request transfer of only one or more subranges of the
/// selected representation data, rather than the entire selected
/// representation data.
///
/// # ABNF
/// ```plain
/// Range =	byte-ranges-specifier / other-ranges-specifier
/// other-ranges-specifier = other-range-unit "=" other-range-set
/// other-range-set = 1*VCHAR
///
/// bytes-unit = "bytes"
///
/// byte-ranges-specifier = bytes-unit "=" byte-range-set
/// byte-range-set = 1#(byte-range-spec / suffix-byte-range-spec)
/// byte-range-spec = first-byte-pos "-" [last-byte-pos]
/// first-byte-pos = 1*DIGIT
/// last-byte-pos = 1*DIGIT
/// ```
///
/// # Example values
/// * `bytes=1000-`
/// * `bytes=-2000`
/// * `bytes=0-1,30-40`
/// * `bytes=0-10,20-90,-100`
/// * `custom_unit=0-123`
/// * `custom_unit=xxx-yyy`
///
/// # Examples
/// ```
/// use hyper::header::{Headers, Range, ByteRangeSpec};
///
/// let mut headers = Headers::new();
/// headers.set(Range::Bytes(
///     vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::AllFrom(200)]
/// ));
///
/// headers.clear();
/// headers.set(Range::Unregistered("letters".to_owned(), "a-f".to_owned()));
/// ```
/// ```
/// use hyper::header::{Headers, Range};
///
/// let mut headers = Headers::new();
/// headers.set(Range::bytes(1, 100));
///
/// headers.clear();
/// headers.set(Range::bytes_multi(vec![(1, 100), (200, 300)]));
/// ```
#[derive(PartialEq, Clone, Debug)]
pub enum Range {
    /// Byte range
    Bytes(Vec<ByteRangeSpec>),
    /// Custom range, with unit not registered at IANA
    /// (`other-range-unit`: String , `other-range-set`: String)
    Unregistered(String, String)
}

/// Each `Range::Bytes` header can contain one or more `ByteRangeSpecs`.
/// Each `ByteRangeSpec` defines a range of bytes to fetch
#[derive(PartialEq, Clone, Debug)]
pub enum ByteRangeSpec {
    /// Get all bytes between x and y ("x-y")
    FromTo(u64, u64),
    /// Get all bytes starting from x ("x-")
    AllFrom(u64),
    /// Get last x bytes ("-x")
    Last(u64)
}

impl Range {
    /// Get the most common byte range header ("bytes=from-to")
    pub fn bytes(from: u64, to: u64) -> Range {
        Range::Bytes(vec![ByteRangeSpec::FromTo(from, to)])
    }

    /// Get byte range header with multiple subranges
    /// ("bytes=from1-to1,from2-to2,fromX-toX")
    pub fn bytes_multi(ranges: Vec<(u64, u64)>) -> Range {
        Range::Bytes(ranges.iter().map(|r| ByteRangeSpec::FromTo(r.0, r.1)).collect())
    }
}

impl fmt::Display for ByteRangeSpec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ByteRangeSpec::FromTo(from, to) => write!(f, "{}-{}", from, to),
            ByteRangeSpec::Last(pos) => write!(f, "-{}", pos),
            ByteRangeSpec::AllFrom(pos) => write!(f, "{}-", pos),
        }
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Range::Bytes(ref ranges) => {
                try!(write!(f, "bytes="));

                for (i, range) in ranges.iter().enumerate() {
                    if i != 0 {
                        try!(f.write_str(","));
                    }
                    try!(Display::fmt(range, f));
                }
                Ok(())
            },
            Range::Unregistered(ref unit, ref range_str) => {
                write!(f, "{}={}", unit, range_str)
            },
        }
    }
}

impl FromStr for Range {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<Range> {
        let mut iter = s.splitn(2, '=');

        match (iter.next(), iter.next()) {
            (Some("bytes"), Some(ranges)) => {
                let ranges = from_comma_delimited(ranges);
                if ranges.is_empty() {
                    return Err(::Error::Header);
                }
                Ok(Range::Bytes(ranges))
            }
            (Some(unit), Some(range_str)) if unit != "" && range_str != "" => {
                Ok(Range::Unregistered(unit.to_owned(), range_str.to_owned()))

            },
            _ => Err(::Error::Header)
        }
    }
}

impl FromStr for ByteRangeSpec {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<ByteRangeSpec> {
        let mut parts = s.splitn(2, '-');

        match (parts.next(), parts.next()) {
            (Some(""), Some(end)) => {
                end.parse().or(Err(::Error::Header)).map(ByteRangeSpec::Last)
            },
            (Some(start), Some("")) => {
                start.parse().or(Err(::Error::Header)).map(ByteRangeSpec::AllFrom)
            },
            (Some(start), Some(end)) => {
                match (start.parse(), end.parse()) {
                    (Ok(start), Ok(end)) if start <= end => Ok(ByteRangeSpec::FromTo(start, end)),
                    _ => Err(::Error::Header)
                }
            },
            _ => Err(::Error::Header)
        }
    }
}

fn from_comma_delimited<T: FromStr>(s: &str) -> Vec<T> {
    s.split(',')
        .filter_map(|x| match x.trim() {
            "" => None,
            y => Some(y)
        })
        .filter_map(|x| x.parse().ok())
        .collect()
}

impl Header for Range {

    fn header_name() -> &'static str {
        static NAME: &'static str = "Range";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<Range> {
        from_one_raw_str(raw)
    }

    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }

}

#[test]
fn test_parse_bytes_range_valid() {
    let r: Range = Header::parse_header(&"bytes=1-100".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes=1-100,-".into()).unwrap();
    let r3 =  Range::bytes(1, 100);
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"bytes=1-100,200-".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes= 1-100 , 101-xxx,  200- ".into()).unwrap();
    let r3 =  Range::Bytes(
        vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::AllFrom(200)]
    );
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"bytes=1-100,-100".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes=1-100, ,,-100".into()).unwrap();
    let r3 =  Range::Bytes(
        vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::Last(100)]
    );
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
    assert_eq!(r, r2);

}

#[test]
fn test_parse_unregistered_range_valid() {
    let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
    assert_eq!(r, r2);

    let r: Range = Header::parse_header(&"custom=abcd".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "abcd".to_owned());
    assert_eq!(r, r2);

    let r: Range = Header::parse_header(&"custom=xxx-yyy".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "xxx-yyy".to_owned());
    assert_eq!(r, r2);
}

#[test]
fn test_parse_invalid() {
    let r: ::Result<Range> = Header::parse_header(&"bytes=1-a,-".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=1-2-3".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"abc".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=1-100=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"custom=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"=1-100".into());
    assert_eq!(r.ok(), None);
}

#[test]
fn test_fmt() {
    use header::Headers;

    let mut headers = Headers::new();

    headers.set(
        Range::Bytes(
            vec![ByteRangeSpec::FromTo(0, 1000), ByteRangeSpec::AllFrom(2000)]
    ));
    assert_eq!(&headers.to_string(), "Range: bytes=0-1000,2000-\r\n");

    headers.clear();
    headers.set(Range::Bytes(vec![]));

    assert_eq!(&headers.to_string(), "Range: bytes=\r\n");

    headers.clear();
    headers.set(Range::Unregistered("custom".to_owned(), "1-xxx".to_owned()));

    assert_eq!(&headers.to_string(), "Range: custom=1-xxx\r\n");
}

bench_header!(bytes_multi, Range, { vec![b"bytes=1-1001,2001-3001,10001-".to_vec()]});
bench_header!(custom_unit, Range, { vec![b"other=0-100000".to_vec()]});
<commit_msg>feat(header): implement ByteRangeSpec::to_satisfiable_range<commit_after>use std::fmt::{self, Display};
use std::str::FromStr;

use header::{Header, Raw};
use header::parsing::{from_one_raw_str};

/// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1)
///
/// The "Range" header field on a GET request modifies the method
/// semantics to request transfer of only one or more subranges of the
/// selected representation data, rather than the entire selected
/// representation data.
///
/// # ABNF
/// ```plain
/// Range =	byte-ranges-specifier / other-ranges-specifier
/// other-ranges-specifier = other-range-unit "=" other-range-set
/// other-range-set = 1*VCHAR
///
/// bytes-unit = "bytes"
///
/// byte-ranges-specifier = bytes-unit "=" byte-range-set
/// byte-range-set = 1#(byte-range-spec / suffix-byte-range-spec)
/// byte-range-spec = first-byte-pos "-" [last-byte-pos]
/// first-byte-pos = 1*DIGIT
/// last-byte-pos = 1*DIGIT
/// ```
///
/// # Example values
/// * `bytes=1000-`
/// * `bytes=-2000`
/// * `bytes=0-1,30-40`
/// * `bytes=0-10,20-90,-100`
/// * `custom_unit=0-123`
/// * `custom_unit=xxx-yyy`
///
/// # Examples
/// ```
/// use hyper::header::{Headers, Range, ByteRangeSpec};
///
/// let mut headers = Headers::new();
/// headers.set(Range::Bytes(
///     vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::AllFrom(200)]
/// ));
///
/// headers.clear();
/// headers.set(Range::Unregistered("letters".to_owned(), "a-f".to_owned()));
/// ```
/// ```
/// use hyper::header::{Headers, Range};
///
/// let mut headers = Headers::new();
/// headers.set(Range::bytes(1, 100));
///
/// headers.clear();
/// headers.set(Range::bytes_multi(vec![(1, 100), (200, 300)]));
/// ```
#[derive(PartialEq, Clone, Debug)]
pub enum Range {
    /// Byte range
    Bytes(Vec<ByteRangeSpec>),
    /// Custom range, with unit not registered at IANA
    /// (`other-range-unit`: String , `other-range-set`: String)
    Unregistered(String, String)
}

/// Each `Range::Bytes` header can contain one or more `ByteRangeSpecs`.
/// Each `ByteRangeSpec` defines a range of bytes to fetch
#[derive(PartialEq, Clone, Debug)]
pub enum ByteRangeSpec {
    /// Get all bytes between x and y ("x-y")
    FromTo(u64, u64),
    /// Get all bytes starting from x ("x-")
    AllFrom(u64),
    /// Get last x bytes ("-x")
    Last(u64)
}

impl ByteRangeSpec {
    /// Given the full length of the entity, attempt to normalize the byte range
    /// into an satisfiable end-inclusive (from, to) range.
    ///
    /// The resulting range is guaranteed to be a satisfiable range within the bounds
    /// of `0 <= from <= to < full_length`.
    ///
    /// If the byte range is deemed unsatisfiable, `None` is returned.
    /// An unsatisfiable range is generally cause for a server to either reject
    /// the client request with a `416 Range Not Satisfiable` status code, or to
    /// simply ignore the range header and serve the full entity using a `200 OK`
    /// status code.
    ///
    /// This function closely follows [RFC 7233][1] section 2.1.
    /// As such, it considers ranges to be satisfiable if they meet the following
    /// conditions:
    ///
    /// > If a valid byte-range-set includes at least one byte-range-spec with
    /// a first-byte-pos that is less than the current length of the
    /// representation, or at least one suffix-byte-range-spec with a
    /// non-zero suffix-length, then the byte-range-set is satisfiable.
    /// Otherwise, the byte-range-set is unsatisfiable.
    ///
    /// The function also computes remainder ranges based on the RFC:
    ///
    /// > If the last-byte-pos value is
    /// absent, or if the value is greater than or equal to the current
    /// length of the representation data, the byte range is interpreted as
    /// the remainder of the representation (i.e., the server replaces the
    /// value of last-byte-pos with a value that is one less than the current
    /// length of the selected representation).
    ///
    /// [1]: https://tools.ietf.org/html/rfc7233
    pub fn to_satisfiable_range(&self, full_length: u64) -> Option<(u64, u64)> {
        // If the full length is zero, there is no satisfiable end-inclusive range.
        if full_length == 0 {
            return None;
        }
        match self {
            &ByteRangeSpec::FromTo(from, to) => {
                if from < full_length && from <= to {
                    Some((from, ::std::cmp::min(to, full_length - 1)))
                } else {
                    None
                }
            },
            &ByteRangeSpec::AllFrom(from) => {
                if from < full_length {
                    Some((from, full_length - 1))
                } else {
                    None
                }
            },
            &ByteRangeSpec::Last(last) => {
                if last > 0 {
                    // From the RFC: If the selected representation is shorter
                    // than the specified suffix-length,
                    // the entire representation is used.
                    if last > full_length {
                        Some((0, full_length - 1))
                    } else {
                        Some((full_length - last, full_length - 1))
                    }
                } else {
                    None
                }
            }
        }
    }
}

impl Range {
    /// Get the most common byte range header ("bytes=from-to")
    pub fn bytes(from: u64, to: u64) -> Range {
        Range::Bytes(vec![ByteRangeSpec::FromTo(from, to)])
    }

    /// Get byte range header with multiple subranges
    /// ("bytes=from1-to1,from2-to2,fromX-toX")
    pub fn bytes_multi(ranges: Vec<(u64, u64)>) -> Range {
        Range::Bytes(ranges.iter().map(|r| ByteRangeSpec::FromTo(r.0, r.1)).collect())
    }
}

impl fmt::Display for ByteRangeSpec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ByteRangeSpec::FromTo(from, to) => write!(f, "{}-{}", from, to),
            ByteRangeSpec::Last(pos) => write!(f, "-{}", pos),
            ByteRangeSpec::AllFrom(pos) => write!(f, "{}-", pos),
        }
    }
}

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Range::Bytes(ref ranges) => {
                try!(write!(f, "bytes="));

                for (i, range) in ranges.iter().enumerate() {
                    if i != 0 {
                        try!(f.write_str(","));
                    }
                    try!(Display::fmt(range, f));
                }
                Ok(())
            },
            Range::Unregistered(ref unit, ref range_str) => {
                write!(f, "{}={}", unit, range_str)
            },
        }
    }
}

impl FromStr for Range {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<Range> {
        let mut iter = s.splitn(2, '=');

        match (iter.next(), iter.next()) {
            (Some("bytes"), Some(ranges)) => {
                let ranges = from_comma_delimited(ranges);
                if ranges.is_empty() {
                    return Err(::Error::Header);
                }
                Ok(Range::Bytes(ranges))
            }
            (Some(unit), Some(range_str)) if unit != "" && range_str != "" => {
                Ok(Range::Unregistered(unit.to_owned(), range_str.to_owned()))

            },
            _ => Err(::Error::Header)
        }
    }
}

impl FromStr for ByteRangeSpec {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<ByteRangeSpec> {
        let mut parts = s.splitn(2, '-');

        match (parts.next(), parts.next()) {
            (Some(""), Some(end)) => {
                end.parse().or(Err(::Error::Header)).map(ByteRangeSpec::Last)
            },
            (Some(start), Some("")) => {
                start.parse().or(Err(::Error::Header)).map(ByteRangeSpec::AllFrom)
            },
            (Some(start), Some(end)) => {
                match (start.parse(), end.parse()) {
                    (Ok(start), Ok(end)) if start <= end => Ok(ByteRangeSpec::FromTo(start, end)),
                    _ => Err(::Error::Header)
                }
            },
            _ => Err(::Error::Header)
        }
    }
}

fn from_comma_delimited<T: FromStr>(s: &str) -> Vec<T> {
    s.split(',')
        .filter_map(|x| match x.trim() {
            "" => None,
            y => Some(y)
        })
        .filter_map(|x| x.parse().ok())
        .collect()
}

impl Header for Range {

    fn header_name() -> &'static str {
        static NAME: &'static str = "Range";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<Range> {
        from_one_raw_str(raw)
    }

    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }

}

#[test]
fn test_parse_bytes_range_valid() {
    let r: Range = Header::parse_header(&"bytes=1-100".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes=1-100,-".into()).unwrap();
    let r3 =  Range::bytes(1, 100);
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"bytes=1-100,200-".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes= 1-100 , 101-xxx,  200- ".into()).unwrap();
    let r3 =  Range::Bytes(
        vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::AllFrom(200)]
    );
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"bytes=1-100,-100".into()).unwrap();
    let r2: Range = Header::parse_header(&"bytes=1-100, ,,-100".into()).unwrap();
    let r3 =  Range::Bytes(
        vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::Last(100)]
    );
    assert_eq!(r, r2);
    assert_eq!(r2, r3);

    let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
    assert_eq!(r, r2);

}

#[test]
fn test_parse_unregistered_range_valid() {
    let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
    assert_eq!(r, r2);

    let r: Range = Header::parse_header(&"custom=abcd".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "abcd".to_owned());
    assert_eq!(r, r2);

    let r: Range = Header::parse_header(&"custom=xxx-yyy".into()).unwrap();
    let r2 =  Range::Unregistered("custom".to_owned(), "xxx-yyy".to_owned());
    assert_eq!(r, r2);
}

#[test]
fn test_parse_invalid() {
    let r: ::Result<Range> = Header::parse_header(&"bytes=1-a,-".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=1-2-3".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"abc".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=1-100=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"bytes=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"custom=".into());
    assert_eq!(r.ok(), None);

    let r: ::Result<Range> = Header::parse_header(&"=1-100".into());
    assert_eq!(r.ok(), None);
}

#[test]
fn test_fmt() {
    use header::Headers;

    let mut headers = Headers::new();

    headers.set(
        Range::Bytes(
            vec![ByteRangeSpec::FromTo(0, 1000), ByteRangeSpec::AllFrom(2000)]
    ));
    assert_eq!(&headers.to_string(), "Range: bytes=0-1000,2000-\r\n");

    headers.clear();
    headers.set(Range::Bytes(vec![]));

    assert_eq!(&headers.to_string(), "Range: bytes=\r\n");

    headers.clear();
    headers.set(Range::Unregistered("custom".to_owned(), "1-xxx".to_owned()));

    assert_eq!(&headers.to_string(), "Range: custom=1-xxx\r\n");
}

#[test]
fn test_byte_range_spec_to_satisfiable_range() {
    assert_eq!(Some((0, 0)), ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(3));
    assert_eq!(Some((1, 2)), ByteRangeSpec::FromTo(1, 2).to_satisfiable_range(3));
    assert_eq!(Some((1, 2)), ByteRangeSpec::FromTo(1, 5).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::FromTo(3, 3).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::FromTo(2, 1).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(0));

    assert_eq!(Some((0, 2)), ByteRangeSpec::AllFrom(0).to_satisfiable_range(3));
    assert_eq!(Some((2, 2)), ByteRangeSpec::AllFrom(2).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::AllFrom(3).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::AllFrom(5).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::AllFrom(0).to_satisfiable_range(0));

    assert_eq!(Some((1, 2)), ByteRangeSpec::Last(2).to_satisfiable_range(3));
    assert_eq!(Some((2, 2)), ByteRangeSpec::Last(1).to_satisfiable_range(3));
    assert_eq!(Some((0, 2)), ByteRangeSpec::Last(5).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::Last(0).to_satisfiable_range(3));
    assert_eq!(None, ByteRangeSpec::Last(2).to_satisfiable_range(0));
}

bench_header!(bytes_multi, Range, { vec![b"bytes=1-1001,2001-3001,10001-".to_vec()]});
bench_header!(custom_unit, Range, { vec![b"other=0-100000".to_vec()]});
<|endoftext|>


<commit_before>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use template::{Helper};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};

fn build_path (path: &String, param: &Option<&String>, key: &str) -> String {
    let mut new_path = String::new();
    new_path.push_str(path.as_slice());
    new_path.push_str("/");
    new_path.push_str(param.unwrap().as_slice());
    new_path.push_str("[");
    new_path.push_str(key);
    new_path.push_str("]");
    new_path
}

#[deriving(Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let param = h.params().get(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"error\""));
        }

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param.unwrap());
                let mut buffer = String::new();

                rc.promote_local_vars();

                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in range(0, len) {
                            if i == 0u {
                                rc.set_local_var("@first".to_string(), true.to_json());
                            }
                            if len > 1 && i == (len-1) {
                                rc.set_local_var("@last".to_string(), true.to_json());
                            }
                            rc.set_local_var("@index".to_string(), i.to_json());
                            // context change
                            let new_path = build_path(&path, &param, i.to_string().as_slice());
                            rc.set_path(new_path);

                            match t.render(c, r, rc) {
                                Ok(r) => {
                                    buffer.push_str(r.as_slice());
                                }
                                Err(r) => {
                                    return Err(r);
                                }
                            }

                        }
                        Ok(buffer)
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            if first {
                                rc.set_local_var("@first".to_string(), true.to_json());
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = build_path(&path, &param, k.to_string().as_slice());
                            match t.render(c, r, rc) {
                                Ok(r) => {
                                    buffer.push_str(r.as_slice());
                                }
                                Err(r) => {
                                    return Err(r);
                                }
                            }
                        }

                        Ok(buffer)
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(EMPTY.to_string())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;
<commit_msg>fixed key issue in each, added tests<commit_after>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use template::{Helper};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};

#[deriving(Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let param = h.params().get(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"each\""));
        }

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param.unwrap());
                let mut buffer = String::new();

                rc.promote_local_vars();

                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in range(0, len) {
                            rc.set_local_var("@first".to_string(), (i==0u).to_json());
                            rc.set_local_var("@last".to_string(), (len>1 && i == len-1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());
                            // context change
                            let index_visitor_path = format!("[{}]", i);
                            let new_path = format!("{}/{}[{}]", path, param.unwrap(), i);
                            rc.set_path(new_path);

                            match t.render(c, r, rc) {
                                Ok(r) => {
                                    buffer.push_str(r.as_slice());
                                }
                                Err(r) => {
                                    return Err(r);
                                }
                            }

                        }
                        Ok(buffer)
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = format!("{}/{}/{}", path, param.unwrap(), k);
                            rc.set_path(new_path);
                            match t.render(c, r, rc) {
                                Ok(r) => {
                                    buffer.push_str(r.as_slice());
                                }
                                Err(r) => {
                                    return Err(r);
                                }
                            }
                        }

                        Ok(buffer)
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(EMPTY.to_string())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use helpers::{EACH_HELPER};

    use std::collections::BTreeMap;

    #[test]
    fn test_if() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}".to_string()).unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}".to_string()).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", &t0);
        handlebars.register_template("t1", &t1);
        handlebars.register_helper("each", box EACH_HELPER);

        let r0 = handlebars.render("t0", &vec![1u, 2u, 3u]);
        assert_eq!(r0.unwrap(), "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m :BTreeMap<String, uint> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

}
<|endoftext|>


<commit_before><commit_msg>add another lichess reponse benchmark<commit_after><|endoftext|>


<commit_before>use graph::{Edge, Graph};
use adjacency_matrix::AdjacencyMatrix;

// maximum_flow returns the maximum flow from source to sink in g.
pub fn maximum_flow(g: &Graph, source: usize, sink: usize) -> u32 {
    // Initially, the residual flow graph of g is just the same as g.
    let mut residual_flow_graph = AdjacencyMatrix::from_graph(g);

    let mut flow = 0;
    while let Some(path_capacity) = residual_flow_graph.add_augmenting_path(source, sink) {
        flow += path_capacity;
    }
    flow
}

impl AdjacencyMatrix {
    // addAugmentingPath looks for an augmenting path from source to sink in the residual flow
    // graph.
    // If an augmenting path is found, addAugmentingPath updates the residual flow graph to reflect
    // the addition of the augmenting path, and returns the capacity of the augmenting path.
    // If no augmenting path is found, addAugmentingPath returns None.
    fn add_augmenting_path(&mut self, source: usize, sink: usize) -> Option<u32> {
        let mut parents = vec![None; self.size()];

        for Edge { x, y } in self.breadth_first_search(source) {
            parents[y] = Some(x);
            if y == sink {
                // Abort the BFS.
                break;
            }
        }

        // self.breadth_first_search(source, |Edge { x, y }| {
        //     parents[y] = x;
        //     // Return true to abort the BFS.
        //     y == sink
        // });

        self.substract_path(&parents, sink)
    }

    // substractPath substracts the path described by parents and end from the residual flow graph,
    // and returns the capacity of the path.
    fn substract_path(&mut self, parents: &Vec<Option<usize>>, end: usize) -> Option<u32> {
        let capacity = self.path_capacity(parents, end);

        if let Some(c) = capacity {
            for Edge {x, y} in edges(parents, end) {
                self[x][y] -= c;
                self[y][x] += c;
            }
        }

        capacity
    }

    // pathCapacity returns the capacity of the path described by parents and end in the residual
    // flow graph.
    fn path_capacity(&self, parents: &Vec<Option<usize>>, end: usize) -> Option<u32> {
        let edges = edges(parents, end);
        let capacities = edges.iter().map(|edge| self[edge.x][edge.y]);
        capacities.min()
    }
}

// edges returns the edges of the path described by parents and end.
fn edges(parents: &Vec<Option<usize>>, mut end: usize) -> Vec<Edge> {
    let mut edges = vec![];

    while let Some(parent) = parents[end] {
        edges.push(Edge { x: parent, y: end });
        end = parent;
    }

    edges.reverse();
    edges
}
<commit_msg>[edge_connectivity/rust] Add explanation for commented-out callback-based BFS<commit_after>use graph::{Edge, Graph};
use adjacency_matrix::AdjacencyMatrix;

// maximum_flow returns the maximum flow from source to sink in g.
pub fn maximum_flow(g: &Graph, source: usize, sink: usize) -> u32 {
    // Initially, the residual flow graph of g is just the same as g.
    let mut residual_flow_graph = AdjacencyMatrix::from_graph(g);

    let mut flow = 0;
    while let Some(path_capacity) = residual_flow_graph.add_augmenting_path(source, sink) {
        flow += path_capacity;
    }
    flow
}

impl AdjacencyMatrix {
    // addAugmentingPath looks for an augmenting path from source to sink in the residual flow
    // graph.
    // If an augmenting path is found, addAugmentingPath updates the residual flow graph to reflect
    // the addition of the augmenting path, and returns the capacity of the augmenting path.
    // If no augmenting path is found, addAugmentingPath returns None.
    fn add_augmenting_path(&mut self, source: usize, sink: usize) -> Option<u32> {
        let mut parents = vec![None; self.size()];

        for Edge { x, y } in self.breadth_first_search(source) {
            parents[y] = Some(x);
            if y == sink {
                // Abort the BFS.
                break;
            }
        }

        // This is how we would use the callback-based BFS commented out in adjacency_matrix.rs.

        // self.breadth_first_search(source, |Edge { x, y }| {
        //     parents[y] = x;
        //     // Return true to abort the BFS.
        //     y == sink
        // });

        self.substract_path(&parents, sink)
    }

    // substractPath substracts the path described by parents and end from the residual flow graph,
    // and returns the capacity of the path.
    fn substract_path(&mut self, parents: &Vec<Option<usize>>, end: usize) -> Option<u32> {
        let capacity = self.path_capacity(parents, end);

        if let Some(c) = capacity {
            for Edge {x, y} in edges(parents, end) {
                self[x][y] -= c;
                self[y][x] += c;
            }
        }

        capacity
    }

    // pathCapacity returns the capacity of the path described by parents and end in the residual
    // flow graph.
    fn path_capacity(&self, parents: &Vec<Option<usize>>, end: usize) -> Option<u32> {
        let edges = edges(parents, end);
        let capacities = edges.iter().map(|edge| self[edge.x][edge.y]);
        capacities.min()
    }
}

// edges returns the edges of the path described by parents and end.
fn edges(parents: &Vec<Option<usize>>, mut end: usize) -> Vec<Edge> {
    let mut edges = vec![];

    while let Some(parent) = parents[end] {
        edges.push(Edge { x: parent, y: end });
        end = parent;
    }

    edges.reverse();
    edges
}
<|endoftext|>


<commit_before>use std::sync::atomic::{self, Ordering};
use std::{marker, ptr, mem};

use super::{Owned, Shared, Guard};

/// Convert `Option<Shared<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_shared_into_raw<T>(val: Option<Shared<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut())
}

/// Convert `Option<Owned<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_owned_into_raw<T>(val: Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut());
    // This is absolutely crucial in order to avoid the returned pointer from being dangling.
    mem::forget(val);

    ptr
}

/// Convert `&Option<Owned<T>>` into `*mut T`.
///
/// `&None` maps to the null pointer.
#[inline]
fn opt_owned_as_raw<T>(val: &Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut())
}

/// Like `std::sync::atomic::AtomicPtr`.
///
/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
/// the `Owned` and `Shared` types.
#[derive(Debug)]
pub struct Atomic<T> {
    /// The inner atomic pointer.
    ptr: atomic::AtomicPtr<T>,
    /// A phantom marker to fix certain compiler bugs.
    // TODO
    _marker: marker::PhantomData<*const ()>,
}

impl<T> Atomic<T> {
    /// Create a new, null atomic pointer.
    #[cfg(feature = "nightly")]
    pub const fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: marker::PhantomData,
        }
    }

    /// Create a new, null atomic pointer.
    #[cfg(not(feature = "nightly"))]
    pub fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: marker::PhantomData,
        }
    }

    /// Create a new atomic pointer.
    ///
    /// This allocates `data` on the heap and creates an atomic pointer to it.
    pub fn new(data: T) -> Atomic<T> {
        Atomic {
            // As the data has to be stored _somewhere_, we have to allocate it to the heap.
            ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))),
            _marker: marker::PhantomData,
        }
    }

    /// Do an atomic load with a given memory ordering.
    ///
    /// In order to perform the load, we must pass in a borrow of a `Guard`. This is a way of
    /// guaranteeing that the thread has pinned the epoch for the entire lifetime `'a`. In return,
    /// you get an optional `Shared` pointer back (`None` if the `Atomic` is currently null), with
    /// lifetime tied to the guard.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Release` or `AcqRel`.
    pub fn load<'a>(&self, ord: Ordering, guard: &'a Guard) -> Option<Shared<'a, T>> {
        // Load the pointer.
        unsafe { self.ptr.load(ord).as_ref() }
            // Construct the `Shared` pointer.
            .map(|x| guard.new_shared(x))
    }

    /// Do an atomic store with a given memory ordering.
    ///
    /// This transfers ownership of the given `Owned` pointer, if any. Since no lifetime
    /// information is acquired, no `Guard` value is needed.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store(&self, val: Option<Owned<T>>, ord: Ordering) {
        self.ptr.store(opt_owned_into_raw(val), ord)
    }

    /// Do an atomic store with the given memory ordering and get a shared reference.
    ///
    /// This transfers ownership of the given `Owned` pointer, yielding a `Shared` reference to it.
    /// Since the reference is valid only for the curent epoch, it's lifetime is tied to a `Guard`
    /// value.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_and_ref<'a>(&self, val: Owned<T>, ord: Ordering, guard: &'a Guard) -> Shared<'a, T> {
        let shared = guard.new_shared(&*val);
        self.store_shared(Some(shared), ord);
        shared
    }

    /// Do an atomic store of a `Shared` pointer with a given memory ordering.
    ///
    /// This operation does not require a guard, because it does not yield any new information
    /// about the lifetime of a pointer.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_shared(&self, val: Option<Shared<T>>, ord: Ordering) {
        self.ptr.store(opt_shared_into_raw(val), ord)
    }

    /// Atomically compare the value against `old` and swap it with `new` if matching.
    ///
    /// This is commonly refered to as 'CAS'. `self` is compared to `old`. If equal, `self` is set
    /// to `new` and `Ok(())` returned. Otherwise, `Err(actual_value)` is returned (with
    /// `actual_value` being the read value of `self`).
    ///
    /// All this is done atomically according to the atomic ordering specified in `ord`.
    pub fn compare_and_swap<'a>(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering, guard: &'a Guard)
        -> Result<(), Option<Shared<'a, T>>> {
        // Convert `old` into a raw pointer.
        let old = opt_shared_into_raw(old);
        // Compare it against `new`.
        let found = self.ptr.compare_and_swap(old, opt_shared_into_raw(new), ord);

        if found == old {
            // They matched, so the CAS succeeded.
            Ok(())
        } else {
            // They did not match, so we will return a shared pointer to the value.
            Err(unsafe { found.as_ref() }.map(|x| guard.new_shared(x)))
        }
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering.
    ///
    /// As with `store`, this operation does not require a guard; it produces no new lifetime
    /// information. The `Result` indicates whether the CAS succeeded; if not, ownership of the
    /// `new` pointer is returned to the caller.
    pub fn compare_and_set(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
        -> Result<(), Option<Owned<T>>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_owned_as_raw(&new), ord)
            == opt_shared_into_raw(old) {
            // This is crucial to avoid `new`'s destructor being called, which could cause an
            // dangling pointer to leak into safe API.
            mem::forget(new);
            Ok(())
        } else {
            Err(new)
        }
   }

    /// Renamed to `compare_and_set`.
    #[deprecated]
    pub fn cas(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
        -> Result<(), Option<Owned<T>>> {
        self.compare_and_set(old, new, ord)
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering and get
    /// a shared reference to it.
    ///
    /// This operation is analogous to `store_and_ref`.
    pub fn compare_and_set_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>, ord: Ordering, guard: &'a Guard)
        -> Result<Shared<'a, T>, Owned<T>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord)
            == opt_shared_into_raw(old) {
            Ok(guard.new_shared(&new))
        } else {
            Err(new)
        }
    }

    /// Renamed to `compare_and_set_ref`.
    #[deprecated]
    pub fn cas_and_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>, ord: Ordering, guard: &'a Guard)
        -> Result<Shared<'a, T>, Owned<T>> {
        self.compare_and_set_ref(old, new, ord, guard)
    }

    /// compare-and-set from a `Shared` to another `Shared` pointer with a given memory ordering.
    ///
    /// The boolean return value is `true` when the CAS is successful.
    pub fn compare_and_set_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
        -> bool {
        self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_shared_into_raw(new), ord)
            == opt_shared_into_raw(old)
    }

    /// Renamed to `compare_and_set_shared`.
    #[deprecated]
    pub fn cas_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
                      -> bool {
        self.compare_and_set_shared(old, new, ord)
    }

    /// Do an atomic swap with an `Owned` pointer with the given memory ordering.
    pub fn swap<'a>(&self, new: Option<Owned<T>>, ord: Ordering, guard: &'a Guard)
        -> Option<Shared<'a, T>> {
        unsafe {
            // Swap the inner.
            self.ptr.swap(opt_owned_into_raw(new), ord).as_ref()
                // Construct the `Shared` pointer.
                .map(|x| guard.new_shared(&*x))
        }
    }

    /// Do an atomic swap with a `Shared` pointer with a given memory ordering.
    pub fn swap_shared<'a>(&self, new: Option<Shared<T>>, ord: Ordering, guard: &'a Guard)
        -> Option<Shared<'a, T>> {
        unsafe {
            // Swap the inner.
            self.ptr.swap(opt_shared_into_raw(new), ord).as_ref()
                // Construct the `Shared` pointer.
                .map(|x| guard.new_shared(&*x))
        }
    }
}

impl<T> Default for Atomic<T> {
    fn default() -> Atomic<T> {
        Atomic::null()
    }
}

unsafe impl<T: Sync> Send for Atomic<T> {}
unsafe impl<T: Sync> Sync for Atomic<T> {}
<commit_msg>Remove deprecated methods.<commit_after>use std::sync::atomic::{self, Ordering};
use std::{marker, ptr, mem};

use super::{Owned, Shared, Guard};

/// Convert `Option<Shared<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_shared_into_raw<T>(val: Option<Shared<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut())
}

/// Convert `Option<Owned<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_owned_into_raw<T>(val: Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut());
    // This is absolutely crucial in order to avoid the returned pointer from being dangling.
    mem::forget(val);

    ptr
}

/// Convert `&Option<Owned<T>>` into `*mut T`.
///
/// `&None` maps to the null pointer.
#[inline]
fn opt_owned_as_raw<T>(val: &Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut())
}

/// Like `std::sync::atomic::AtomicPtr`.
///
/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
/// the `Owned` and `Shared` types.
#[derive(Debug)]
pub struct Atomic<T> {
    /// The inner atomic pointer.
    ptr: atomic::AtomicPtr<T>,
    /// A phantom marker to fix certain compiler bugs.
    // TODO
    _marker: marker::PhantomData<*const ()>,
}

impl<T> Atomic<T> {
    /// Create a new, null atomic pointer.
    #[cfg(feature = "nightly")]
    pub const fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: marker::PhantomData,
        }
    }

    /// Create a new, null atomic pointer.
    #[cfg(not(feature = "nightly"))]
    pub fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: marker::PhantomData,
        }
    }

    /// Create a new atomic pointer.
    ///
    /// This allocates `data` on the heap and creates an atomic pointer to it.
    pub fn new(data: T) -> Atomic<T> {
        Atomic {
            // As the data has to be stored _somewhere_, we have to allocate it to the heap.
            ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))),
            _marker: marker::PhantomData,
        }
    }

    /// Do an atomic load with a given memory ordering.
    ///
    /// In order to perform the load, we must pass in a borrow of a `Guard`. This is a way of
    /// guaranteeing that the thread has pinned the epoch for the entire lifetime `'a`. In return,
    /// you get an optional `Shared` pointer back (`None` if the `Atomic` is currently null), with
    /// lifetime tied to the guard.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Release` or `AcqRel`.
    pub fn load<'a>(&self, ord: Ordering, guard: &'a Guard) -> Option<Shared<'a, T>> {
        // Load the pointer.
        unsafe { self.ptr.load(ord).as_ref() }
            // Construct the `Shared` pointer.
            .map(|x| guard.new_shared(x))
    }

    /// Do an atomic store with a given memory ordering.
    ///
    /// This transfers ownership of the given `Owned` pointer, if any. Since no lifetime
    /// information is acquired, no `Guard` value is needed.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store(&self, val: Option<Owned<T>>, ord: Ordering) {
        self.ptr.store(opt_owned_into_raw(val), ord)
    }

    /// Do an atomic store with the given memory ordering and get a shared reference.
    ///
    /// This transfers ownership of the given `Owned` pointer, yielding a `Shared` reference to it.
    /// Since the reference is valid only for the curent epoch, it's lifetime is tied to a `Guard`
    /// value.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_and_ref<'a>(&self, val: Owned<T>, ord: Ordering, guard: &'a Guard) -> Shared<'a, T> {
        let shared = guard.new_shared(&*val);
        self.store_shared(Some(shared), ord);
        shared
    }

    /// Do an atomic store of a `Shared` pointer with a given memory ordering.
    ///
    /// This operation does not require a guard, because it does not yield any new information
    /// about the lifetime of a pointer.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_shared(&self, val: Option<Shared<T>>, ord: Ordering) {
        self.ptr.store(opt_shared_into_raw(val), ord)
    }

    /// Atomically compare the value against `old` and swap it with `new` if matching.
    ///
    /// This is commonly refered to as 'CAS'. `self` is compared to `old`. If equal, `self` is set
    /// to `new` and `Ok(())` returned. Otherwise, `Err(actual_value)` is returned (with
    /// `actual_value` being the read value of `self`).
    ///
    /// All this is done atomically according to the atomic ordering specified in `ord`.
    pub fn compare_and_swap<'a>(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering, guard: &'a Guard)
        -> Result<(), Option<Shared<'a, T>>> {
        // Convert `old` into a raw pointer.
        let old = opt_shared_into_raw(old);
        // Compare it against `new`.
        let found = self.ptr.compare_and_swap(old, opt_shared_into_raw(new), ord);

        if found == old {
            // They matched, so the CAS succeeded.
            Ok(())
        } else {
            // They did not match, so we will return a shared pointer to the value.
            Err(unsafe { found.as_ref() }.map(|x| guard.new_shared(x)))
        }
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering.
    ///
    /// As with `store`, this operation does not require a guard; it produces no new lifetime
    /// information. The `Result` indicates whether the CAS succeeded; if not, ownership of the
    /// `new` pointer is returned to the caller.
    pub fn compare_and_set(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
        -> Result<(), Option<Owned<T>>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_owned_as_raw(&new), ord)
            == opt_shared_into_raw(old) {
            // This is crucial to avoid `new`'s destructor being called, which could cause an
            // dangling pointer to leak into safe API.
            mem::forget(new);
            Ok(())
        } else {
            Err(new)
        }
   }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering and get
    /// a shared reference to it.
    ///
    /// This operation is analogous to `store_and_ref`.
    pub fn compare_and_set_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>, ord: Ordering, guard: &'a Guard)
        -> Result<Shared<'a, T>, Owned<T>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord)
            == opt_shared_into_raw(old) {
            Ok(guard.new_shared(&new))
        } else {
            Err(new)
        }
    }

    /// compare-and-set from a `Shared` to another `Shared` pointer with a given memory ordering.
    ///
    /// The boolean return value is `true` when the CAS is successful.
    pub fn compare_and_set_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
        -> bool {
        self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_shared_into_raw(new), ord)
            == opt_shared_into_raw(old)
    }

    /// Do an atomic swap with an `Owned` pointer with the given memory ordering.
    pub fn swap<'a>(&self, new: Option<Owned<T>>, ord: Ordering, guard: &'a Guard)
        -> Option<Shared<'a, T>> {
        unsafe {
            // Swap the inner.
            self.ptr.swap(opt_owned_into_raw(new), ord).as_ref()
                // Construct the `Shared` pointer.
                .map(|x| guard.new_shared(&*x))
        }
    }

    /// Do an atomic swap with a `Shared` pointer with a given memory ordering.
    pub fn swap_shared<'a>(&self, new: Option<Shared<T>>, ord: Ordering, guard: &'a Guard)
        -> Option<Shared<'a, T>> {
        unsafe {
            // Swap the inner.
            self.ptr.swap(opt_shared_into_raw(new), ord).as_ref()
                // Construct the `Shared` pointer.
                .map(|x| guard.new_shared(&*x))
        }
    }
}

impl<T> Default for Atomic<T> {
    fn default() -> Atomic<T> {
        Atomic::null()
    }
}

unsafe impl<T: Sync> Send for Atomic<T> {}
unsafe impl<T: Sync> Sync for Atomic<T> {}
<|endoftext|>


<commit_before>//! After a TCP connection is established, the first message sent by each
//! side is an OPEN message.  If the OPEN message is acceptable, a
//! KEEPALIVE message confirming the OPEN is sent back.

mod capability;
pub use self::capability::*;
use types::*;

#[derive(Debug)]
pub struct Open<'a> {
    pub inner: &'a [u8],
}

impl<'a> Open<'a> {
    pub fn new(raw: &'a [u8]) -> Result<Open> {
        if raw.len() < 10 {
            Err(BgpError::BadLength)
        } else {
            Ok(Open {
                inner: raw,
            })
        }
    }

    pub fn version(&self) -> u8 {
        self.inner[0]
    }

    pub fn aut_num(&self) -> u32 {
        (self.inner[1] as u32) << 8 | self.inner[2] as u32
    }

    pub fn hold_time(&self) -> u16 {
        (self.inner[3] as u16) << 8 | self.inner[4] as u16
    }

    pub fn ident(&self) -> u32 {
        (self.inner[5] as u32) << 24 | (self.inner[6] as u32) << 16 |
        (self.inner[7] as u32) <<  8 | (self.inner[8] as u32)
    }

    pub fn params(&self) -> OpenParams {
        OpenParams::new(&self.inner[10..])
    }
}

#[derive(Debug)]
pub enum OpenParam<'a> {
    Capability(Capability<'a>),
    Unknown(u8),
}

#[derive(Debug)]
pub struct OpenParams<'a> {
    pub inner: &'a [u8],
    error: Option<BgpError>,
}

impl<'a> OpenParams<'a> {
    pub fn new(inner: &'a [u8]) -> OpenParams<'a> {
        OpenParams {
            inner: inner,
            error: None,
        }
    }
}

impl<'a> Iterator for OpenParams<'a> {
    type Item = Result<OpenParam<'a>>;

    fn next(&mut self) -> Option<Result<OpenParam<'a>>> {
        if self.error.is_some() {
            return None;
        }
        if self.inner.len() == 0 {
            return None;
        }
        if self.inner.len() < 2 {
            let err = BgpError::BadLength;
            self.error = Some(err);
            return Some(Err(err));
        }
        let param_type = self.inner[0];
        let param_len = self.inner[1] as usize;
        if self.inner.len() < param_len + 2 {
            let err = BgpError::BadLength;
            self.error = Some(err);
            return Some(Err(err));
        }
        let param_value = &self.inner[2..param_len + 2];
        self.inner = &self.inner[param_len + 2..];
        match param_type {
            2 => Some(Ok(OpenParam::Capability(Capability::new(param_value)))),
            n => Some(Ok(OpenParam::Unknown(n))),
        }
    }
}

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

    #[test]
    fn parse_open() {
        let bytes = &[//0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            //0xff, 0xff, 0xff, 0xff, 0x00, 0x41, 0x01,
            0x04, 0xfc, 0x00, 0x00, 0xb4,
            0x0a, 0x00, 0x00, 0x06, 0x24, 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00,
            0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x46,
            0x00, 0x02, 0x06, 0x45, 0x04, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x41,
            0x04, 0x00, 0x00, 0xfc, 0x00];
        let open = Open::new(bytes).unwrap();
        assert_eq!(open.version(), 4);
        assert_eq!(open.aut_num(), 64512);
        assert_eq!(open.hold_time(), 180);
        assert_eq!(open.ident(), 167772166);

        let mut params = open.params();

        let param1 = params.next().unwrap().unwrap();
        match param1 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::MultiProtocol(AFI_IPV4, SAFI_UNICAST) => (),
                    _ => panic!("expected CapabilityType::MultiProtocol")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        let param2 = params.next().unwrap().unwrap();
        match param2 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::Private(128) => (),
                    _ => panic!("expected CapabilityType::RouteRefresh")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        let param3 = params.next().unwrap().unwrap();
        match param3 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::RouteRefresh => (),
                    _ => panic!("expected CapabilityType::RouteRefresh")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        let param4 = params.next().unwrap().unwrap();
        match param4 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::EnhancedRouteRefresh => (),
                    _ => panic!("expected CapabilityType::EnhancedRouteRefresh")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        let param5 = params.next().unwrap().unwrap();
        match param5 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::AddPath => (),
                    _ => panic!("expected CapabilityType::AddPath")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        let param6 = params.next().unwrap().unwrap();
        match param6 {
            OpenParam::Capability(cap) => {
                match cap.capability_type() {
                    CapabilityType::FourByteASN => (),
                    _ => panic!("expected CapabilityType::FourByteASN")
                }
            }
            _ => panic!("expected OpenParam::Capability")
        }

        assert!(params.next().is_none());
    }
}
<commit_msg>compress tests<commit_after>//! After a TCP connection is established, the first message sent by each
//! side is an OPEN message.  If the OPEN message is acceptable, a
//! KEEPALIVE message confirming the OPEN is sent back.

mod capability;
pub use self::capability::*;
use types::*;

#[derive(Debug)]
pub struct Open<'a> {
    pub inner: &'a [u8],
}

impl<'a> Open<'a> {
    pub fn new(raw: &'a [u8]) -> Result<Open> {
        if raw.len() < 10 {
            Err(BgpError::BadLength)
        } else {
            Ok(Open {
                inner: raw,
            })
        }
    }

    pub fn version(&self) -> u8 {
        self.inner[0]
    }

    pub fn aut_num(&self) -> u32 {
        (self.inner[1] as u32) << 8 | self.inner[2] as u32
    }

    pub fn hold_time(&self) -> u16 {
        (self.inner[3] as u16) << 8 | self.inner[4] as u16
    }

    pub fn ident(&self) -> u32 {
        (self.inner[5] as u32) << 24 | (self.inner[6] as u32) << 16 |
        (self.inner[7] as u32) <<  8 | (self.inner[8] as u32)
    }

    pub fn params(&self) -> OpenParams {
        OpenParams::new(&self.inner[10..])
    }
}

#[derive(Debug)]
pub enum OpenParam<'a> {
    Capability(Capability<'a>),
    Unknown(u8),
}

#[derive(Debug)]
pub struct OpenParams<'a> {
    pub inner: &'a [u8],
    error: Option<BgpError>,
}

impl<'a> OpenParams<'a> {
    pub fn new(inner: &'a [u8]) -> OpenParams<'a> {
        OpenParams {
            inner: inner,
            error: None,
        }
    }
}

impl<'a> Iterator for OpenParams<'a> {
    type Item = Result<OpenParam<'a>>;

    fn next(&mut self) -> Option<Result<OpenParam<'a>>> {
        if self.error.is_some() {
            return None;
        }
        if self.inner.len() == 0 {
            return None;
        }
        if self.inner.len() < 2 {
            let err = BgpError::BadLength;
            self.error = Some(err);
            return Some(Err(err));
        }
        let param_type = self.inner[0];
        let param_len = self.inner[1] as usize;
        if self.inner.len() < param_len + 2 {
            let err = BgpError::BadLength;
            self.error = Some(err);
            return Some(Err(err));
        }
        let param_value = &self.inner[2..param_len + 2];
        self.inner = &self.inner[param_len + 2..];
        match param_type {
            2 => Some(Ok(OpenParam::Capability(Capability::new(param_value)))),
            n => Some(Ok(OpenParam::Unknown(n))),
        }
    }
}

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

    #[test]
    fn parse_open() {
        let bytes = &[//0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            //0xff, 0xff, 0xff, 0xff, 0x00, 0x41, 0x01,
            0x04, 0xfc, 0x00, 0x00, 0xb4,
            0x0a, 0x00, 0x00, 0x06, 0x24, 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00,
            0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x46,
            0x00, 0x02, 0x06, 0x45, 0x04, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x41,
            0x04, 0x00, 0x00, 0xfc, 0x00];
        let open = Open::new(bytes).unwrap();
        assert_eq!(open.version(), 4);
        assert_eq!(open.aut_num(), 64512);
        assert_eq!(open.hold_time(), 180);
        assert_eq!(open.ident(), 167772166);

        let mut params = open.params();

        macro_rules! expect_capability {
            ($a:expr, $p:pat) => {
                match $a {
                    OpenParam::Capability(cap) => {
                        match cap.capability_type() {
                            $p => (),
                            x => panic!("expected {}, got CapabilityType::{:?}", stringify!($p:tt), x)
                        }
                    }
                    _ => panic!("expected OpenParam::Capability")
                }
            }
        }

        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::MultiProtocol(AFI_IPV4, SAFI_UNICAST));
        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::Private(128));
        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::RouteRefresh);
        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::EnhancedRouteRefresh);
        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::AddPath);
        expect_capability!(params.next().unwrap().unwrap(), CapabilityType::FourByteASN);

        assert!(params.next().is_none());
    }
}
<|endoftext|>