<commit_before>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 2.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Sub, Mul, Div, Rem};
    use std::f64::consts::PI;

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Sub for Radians {
        type Output = Self;

        fn sub(self, other: Self) -> Self {
            Radians(self.0 - other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    impl Div<f64> for Radians {
        type Output = Self;

        fn div(self, other: f64) -> Self {
            Radians(self.0 / other)
        }
    }

    impl Rem<f64> for Radians {
        type Output = Self;

        fn rem(self, other: f64) -> Self {
            Radians(self.0 % other)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        White,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::White => [255., 255., 255., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Speed::Instant,
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            if animation.is_some() {
                                unreachable!("The main thread did not wait for the animation to complete before sending another command")
                            }
                            match command {
                                Command::Move {distance} => {
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        let end = math::add(start, [x, y]);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start, end,
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => {
                                    drawing.pen.enabled = enabled;
                                    main_tx.send(Ok(())).unwrap();
                                },
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, 1./path_length);
                                    debug_assert_eq!((math::square_len(direction).sqrt() * 1000.).round(), 1000.);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = Radians(speed.to_rotation());

                                    let heading = turtle.heading;
                                    let current = (heading + speed / 1000. * elapsed) % (2.*PI);
                                    let current = if speed.0.is_infinite() || current > (target_angle % (2.*PI)) {
                                        animation_complete = true;
                                        target_angle
                                    }
                                    else {
                                        let current = if clockwise {
                                            Radians(2.*PI) - current
                                        } else { current };

                                        current
                                    };
                                    assert!(!current.0.is_nan(), "heading became NaN");
                                    turtle.heading = current;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // Draw the turtle's shell
                        let cos = turtle.heading.cos();
                        let sin = turtle.heading.sin();
                        let turtle_x = turtle.position[0];
                        let turtle_y = turtle.position[1];
                        let shell: Vec<_> = [
                            [0., 15.],
                            [10., 0.],
                            [0., -15.],
                        ].into_iter().map(|pt| {
                            // Rotate each point by the heading and add the current turtle position
                            let x = cos * pt[0] - sin * pt[1] + turtle_x;
                            let y = sin * pt[0] + cos * pt[1] + turtle_y;
                            [x, y].to_canvas_coords(center)
                        }).collect();

                        polygon(Color::White.into(), &shell, c.transform, g);
                        for i in 0..shell.len() {
                            let start = shell[i];
                            let end = shell[(i + 1) % shell.len()];

                            line(Color::Black.into(), 1.,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<commit_msg>Got rotation working with Speed::Instant<commit_after>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 2.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Sub, Mul, Div, Rem, Neg};
    use std::f64::consts::PI;

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Sub for Radians {
        type Output = Self;

        fn sub(self, other: Self) -> Self {
            Radians(self.0 - other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    impl Div<f64> for Radians {
        type Output = Self;

        fn div(self, other: f64) -> Self {
            Radians(self.0 / other)
        }
    }

    impl Rem<f64> for Radians {
        type Output = Self;

        fn rem(self, other: f64) -> Self {
            Radians(self.0 % other)
        }
    }

    impl Neg for Radians {
        type Output = Self;

        fn neg(self) -> Self {
            Radians(-self.0)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        White,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::White => [255., 255., 255., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Speed::Instant,
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            if animation.is_some() {
                                unreachable!("The main thread did not wait for the animation to complete before sending another command")
                            }
                            match command {
                                Command::Move {distance} => {
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        let end = math::add(start, [x, y]);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start, end,
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if angle != Radians(0.) {
                                        let target_angle = turtle.heading + if clockwise {
                                            -angle
                                        }
                                        else {
                                            angle
                                        };
                                        assert!(target_angle != turtle.heading);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Rotation {
                                                target_angle,
                                                clockwise,
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Pen {enabled} => {
                                    drawing.pen.enabled = enabled;
                                    main_tx.send(Ok(())).unwrap();
                                },
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, 1./path_length);
                                    debug_assert_eq!((math::square_len(direction).sqrt() * 1000.).round(), 1000.);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = Radians(speed.to_rotation());
                                    let target_angle = target_angle % (2.*PI);

                                    let heading = turtle.heading;
                                    let current = (heading + speed / 1000. * elapsed) % (2.*PI);
                                    let current = if speed.0.is_infinite() || current > target_angle {
                                        animation_complete = true;
                                        target_angle
                                    }
                                    else {
                                        let current = if clockwise {
                                            Radians(2.*PI) - current
                                        } else { current };

                                        current
                                    };
                                    assert!(!current.0.is_nan(), "heading became NaN");
                                    turtle.heading = current;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // Draw the turtle's shell
                        let cos = turtle.heading.cos();
                        let sin = turtle.heading.sin();
                        let turtle_x = turtle.position[0];
                        let turtle_y = turtle.position[1];
                        let shell: Vec<_> = [
                            [0., 15.],
                            [10., 0.],
                            [0., -15.],
                        ].into_iter().map(|pt| {
                            // Rotate each point by the heading and add the current turtle position
                            let x = cos * pt[0] - sin * pt[1] + turtle_x;
                            let y = sin * pt[0] + cos * pt[1] + turtle_y;
                            [x, y].to_canvas_coords(center)
                        }).collect();

                        polygon(Color::White.into(), &shell, c.transform, g);
                        for i in 0..shell.len() {
                            let start = shell[i];
                            let end = shell[(i + 1) % shell.len()];

                            line(Color::Black.into(), 1.,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<|endoftext|>


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

use std::{
    env,
    error::Error,
    fs::{File, OpenOptions},
    io::{Read, Write},
    os::unix::io::AsRawFd,
    str::FromStr,
};

use clap::{App, Arg};
use env_logger::Builder;
use log::LevelFilter;
use nix::{
    fcntl::{flock, FlockArg},
    unistd::getpid,
};

use stratisd::stratis::{run, StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/run/stratisd.pid";
const STRATISD_MIN_PID_PATH: &str = "/run/stratisd-min.pid";

fn parse_args() -> App<'static, 'static> {
    App::new("stratisd-min")
        .version(VERSION)
        .arg(
            Arg::with_name("log_level")
                .empty_values(false)
                .long("--log-level")
                .possible_values(&["trace", "debug", "info", "warn", "error"])
                .help("Sets level for generation of log messages."),
        )
        .arg(
            Arg::with_name("sim")
                .long("--sim")
                .takes_value(false)
                .help("Enables sim engine."),
        )
}

fn get_long_help(app: &mut App<'_, '_>) -> Result<String, Box<dyn Error>> {
    let mut help = Vec::new();
    app.write_long_help(&mut help)?;
    Ok(String::from_utf8(help)?)
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_MIN_PID_PATH)
        .map_err(|err| {
            StratisError::Chained(
                format!(
                    "Failed to create or open the stratisd-min PID file at {}",
                    STRATISD_MIN_PID_PATH
                ),
                Box::new(StratisError::from(err)),
            )
        })?;
    let stratisd_min_file = match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(getpid().to_string().as_bytes())?;
            f
        }
        Err(_) => {
            let mut buf = String::new();

            if f.read_to_string(&mut buf).is_err() {
                buf = "<unreadable>".to_string();
            }

            return Err(StratisError::Msg(format!(
                "Daemon already running with supposed pid: {}",
                buf
            )));
        }
    };

    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
        .map_err(|err| {
            StratisError::Chained(
                format!(
                    "Failed to create or open the stratisd PID file at {}",
                    STRATISD_PID_PATH
                ),
                Box::new(StratisError::from(err)),
            )
        })?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => drop(f),
        Err(_) => {
            let mut buf = String::new();

            if f.read_to_string(&mut buf).is_err() {
                buf = "<unreadable>".to_string();
            }

            return Err(StratisError::Msg(format!(
                "stratisd is already running with supposed pid: {}",
                buf
            )));
        }
    };

    Ok(stratisd_min_file)
}

fn main() -> Result<(), String> {
    fn main_box() -> Result<(), Box<dyn Error>> {
        let mut app = parse_args();
        let help = get_long_help(&mut app)?;
        let args = app.get_matches();

        let _stratisd_min_file = trylock_pid_file()?;

        let mut builder = Builder::new();
        if let Some(log_level) = args.value_of("log_level") {
            builder.filter(
                Some("stratisd"),
                LevelFilter::from_str(log_level)
                    .expect("argument parser only accepts valid log levels"),
            );
        } else if let Ok(s) = env::var("RUST_LOG") {
            builder.parse_filters(&s);
        }
        builder.init();

        if args.is_present("-h") {
            println!("{}", help);
            Ok(())
        } else {
            run(args.is_present("sim"))?;
            Ok(())
        }
    }

    main_box().map_err(|e| e.to_string())
}
<commit_msg>Omit long help<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    env,
    error::Error,
    fs::{File, OpenOptions},
    io::{Read, Write},
    os::unix::io::AsRawFd,
    str::FromStr,
};

use clap::{App, Arg};
use env_logger::Builder;
use log::LevelFilter;
use nix::{
    fcntl::{flock, FlockArg},
    unistd::getpid,
};

use stratisd::stratis::{run, StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/run/stratisd.pid";
const STRATISD_MIN_PID_PATH: &str = "/run/stratisd-min.pid";

fn parse_args() -> App<'static, 'static> {
    App::new("stratisd-min")
        .version(VERSION)
        .arg(
            Arg::with_name("log_level")
                .empty_values(false)
                .long("--log-level")
                .possible_values(&["trace", "debug", "info", "warn", "error"])
                .help("Sets level for generation of log messages."),
        )
        .arg(
            Arg::with_name("sim")
                .long("--sim")
                .takes_value(false)
                .help("Enables sim engine."),
        )
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_MIN_PID_PATH)
        .map_err(|err| {
            StratisError::Chained(
                format!(
                    "Failed to create or open the stratisd-min PID file at {}",
                    STRATISD_MIN_PID_PATH
                ),
                Box::new(StratisError::from(err)),
            )
        })?;
    let stratisd_min_file = match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(getpid().to_string().as_bytes())?;
            f
        }
        Err(_) => {
            let mut buf = String::new();

            if f.read_to_string(&mut buf).is_err() {
                buf = "<unreadable>".to_string();
            }

            return Err(StratisError::Msg(format!(
                "Daemon already running with supposed pid: {}",
                buf
            )));
        }
    };

    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
        .map_err(|err| {
            StratisError::Chained(
                format!(
                    "Failed to create or open the stratisd PID file at {}",
                    STRATISD_PID_PATH
                ),
                Box::new(StratisError::from(err)),
            )
        })?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => drop(f),
        Err(_) => {
            let mut buf = String::new();

            if f.read_to_string(&mut buf).is_err() {
                buf = "<unreadable>".to_string();
            }

            return Err(StratisError::Msg(format!(
                "stratisd is already running with supposed pid: {}",
                buf
            )));
        }
    };

    Ok(stratisd_min_file)
}

fn main() -> Result<(), String> {
    fn main_box() -> Result<(), Box<dyn Error>> {
        let app = parse_args();
        let args = app.get_matches();

        let _stratisd_min_file = trylock_pid_file()?;

        let mut builder = Builder::new();
        if let Some(log_level) = args.value_of("log_level") {
            builder.filter(
                Some("stratisd"),
                LevelFilter::from_str(log_level)
                    .expect("argument parser only accepts valid log levels"),
            );
        } else if let Ok(s) = env::var("RUST_LOG") {
            builder.parse_filters(&s);
        }
        builder.init();

        run(args.is_present("sim"))?;
        Ok(())
    }

    main_box().map_err(|e| e.to_string())
}
<|endoftext|>


<commit_before>extern crate failure;
extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate walkdir;

#[macro_use]
extern crate log;

extern crate gluon;

use std::fs::{create_dir_all, File};
use std::io::{self, Read};
use std::path::{Path, PathBuf};

use failure::ResultExt;

use itertools::Itertools;

use handlebars::{Handlebars, Helper, RenderContext, RenderError};

use serde::Deserialize;

use gluon::base::filename_to_module;
use gluon::base::types::ArcType;
use gluon::base::metadata::Metadata;
use gluon::check::metadata::metadata;
use gluon::{Compiler, Thread};

pub type Error = failure::Error;
pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Serialize, PartialEq, Debug)]
pub struct Module {
    pub name: String,
    pub record: Record,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct Record {
    pub types: Vec<Field>,
    pub values: Vec<Field>,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct Field {
    pub name: String,
    #[serde(rename = "type")]
    pub typ: String,
    pub comment: String,
}

pub fn record(typ: &ArcType, meta: &Metadata) -> Record {
    Record {
        types: typ.type_field_iter()
            .map(|field| Field {
                name: field.name.to_string(),
                typ: field.typ.unresolved_type().to_string(),
                comment: meta.module
                    .get(AsRef::<str>::as_ref(&field.name))
                    .and_then(|meta| meta.comment.as_ref().map(|s| &s[..]))
                    .unwrap_or("")
                    .to_string(),
            })
            .collect(),

        values: typ.row_iter()
            .map(|field| Field {
                name: field.name.to_string(),
                typ: field.typ.to_string(),

                comment: meta.module
                    .get(AsRef::<str>::as_ref(&field.name))
                    .and_then(|meta| meta.comment.as_ref().map(|s| &s[..]))
                    .unwrap_or("")
                    .to_string(),
            })
            .collect(),
    }
}

#[derive(Serialize, Debug)]
pub struct TemplateModule<'a> {
    pub name: &'a str,
    pub record: &'a Record,
    pub sibling_modules: Vec<&'a str>,
}

pub fn generate<W>(reg: &Handlebars, out: &mut W, module: &TemplateModule) -> Result<()>
where
    W: io::Write,
{
    trace!("DOC: {:?}", module);

    let module_template = include_str!("doc/module.html");
    reg.render_template_to_write(module_template, &module, out)
        .with_context(|err| format!("Unable to render {}: {}", module.name, err))?;
    Ok(())
}

fn handlebars() -> Handlebars {
    let mut reg = Handlebars::new();

    fn symbol_link(
        h: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        let param = String::deserialize(h.param(0).unwrap().value())?;
        write!(rc.writer, "/{}.html", param.replace(".", "/"))?;
        Ok(())
    }
    reg.register_helper("symbol_link", Box::new(symbol_link));

    fn breadcrumbs(
        h: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        let param = String::deserialize(h.param(0).unwrap().value())?;
        let parts: Vec<_> = param.split(".").collect();
        for (i, part) in parts.iter().enumerate() {
            write!(
                rc.writer,
                r##"
{}
"##,
                if i + 1 == parts.len() { " active" } else { "" },
                if i + 1 == parts.len() {
                    handlebars::html_escape(&part)
                } else {
                    let path = (0..(parts.len() - i - 2)).map(|_| "../").format("");
                    format!(
                        r##"{}"##,
                        path,
                        handlebars::html_escape(&part)
                    )
                },
            )?;
        }
        Ok(())
    }
    reg.register_helper("breadcrumbs", Box::new(breadcrumbs));

    fn style(
        _: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        write!(rc.writer, r#"
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
               "#)?;
        Ok(())
    }
    reg.register_helper("style", Box::new(style));

    reg
}

pub fn generate_for_path
(thread: &Thread, path: &P, out_path: &Q) -> Result<()>
where
    P: ?Sized + AsRef<Path>,
    Q: ?Sized + AsRef<Path>,
{
    generate_for_path_(thread, path.as_ref(), out_path.as_ref())
}

pub fn generate_for_path_(thread: &Thread, path: &Path, out_path: &Path) -> Result<()> {
    let reg = handlebars();
    let mut directories = Vec::new();
    for entry in walkdir::WalkDir::new(path) {
        let entry = entry?;
        if !entry.file_type().is_file()
            || entry.path().extension().and_then(|ext| ext.to_str()) != Some("glu")
        {
            if entry.file_type().is_dir() {
                directories.push((entry.path().to_owned(), Vec::new()));
            }
            continue;
        }
        let mut input = File::open(&*entry.path()).with_context(|err| {
            format!(
                "Unable to open gluon file `{}`: {}",
                entry.path().display(),
                err
            )
        })?;
        let mut content = String::new();
        input.read_to_string(&mut content)?;

        let name = filename_to_module(entry
            .path()
            .to_str()
            .ok_or_else(|| failure::err_msg("Non-UTF-8 filename"))?);

        let (expr, typ) = Compiler::new().typecheck_str(thread, &name, &content, None)?;
        let (meta, _) = metadata(&*thread.get_env(), &expr);

        create_dir_all(out_path.join(entry.path().parent().unwrap_or(Path::new(""))))?;

        let module = Module {
            name,
            record: record(&typ, &meta),
        };

        directories
            .last_mut()
            .expect("Directory before this file")
            .1
            .push(module);
    }

    #[derive(Serialize)]
    struct Index {
        name: String,
        modules: Vec<String>,
    }

    let module_template = include_str!("doc/index.html");

    for (path, modules) in directories {
        let index_path = out_path.join(&*path).join("index.html");
        trace!("Rendering index: {}", index_path.display());
        let mut doc_file = File::create(&*index_path).with_context(|err| {
            format!(
                "Unable to open output file `{}`: {}",
                index_path.display(),
                err
            )
        })?;

        for module in &modules {
            let out_path =
                out_path.join(PathBuf::from(module.name.replace(".", "/")).with_extension("html"));
            let mut doc_file = File::create(&*out_path).with_context(|err| {
                format!(
                    "Unable to open output file `{}`: {}",
                    out_path.display(),
                    err
                )
            })?;

            generate(
                &reg,
                &mut doc_file,
                &TemplateModule {
                    name: &module.name,
                    record: &module.record,
                    sibling_modules: modules.iter().map(|sibling| &*sibling.name).collect(),
                },
            )?;
        }

        let name = filename_to_module(path.to_str()
            .ok_or_else(|| failure::err_msg("Non-UTF-8 filename"))?);

        reg.render_template_to_write(
            module_template,
            &Index {
                name,
                modules: modules.iter().map(|module| module.name.clone()).collect(),
            },
            &mut doc_file,
        ).with_context(|err| {
            format!("Unable to render index {}: {}", index_path.display(), err)
        })?;
    }

    Ok(())
}
<commit_msg>Use relative paths in documentation<commit_after>extern crate failure;
extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate walkdir;

#[macro_use]
extern crate log;

extern crate gluon;

use std::fs::{create_dir_all, File};
use std::io::{self, Read};
use std::path::{Path, PathBuf};

use failure::ResultExt;

use itertools::Itertools;

use handlebars::{Handlebars, Helper, RenderContext, RenderError};

use serde::Deserialize;

use gluon::base::filename_to_module;
use gluon::base::types::ArcType;
use gluon::base::metadata::Metadata;
use gluon::check::metadata::metadata;
use gluon::{Compiler, Thread};

pub type Error = failure::Error;
pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Serialize, PartialEq, Debug)]
pub struct Module {
    pub name: String,
    pub record: Record,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct Record {
    pub types: Vec<Field>,
    pub values: Vec<Field>,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct Field {
    pub name: String,
    #[serde(rename = "type")]
    pub typ: String,
    pub comment: String,
}

pub fn record(typ: &ArcType, meta: &Metadata) -> Record {
    Record {
        types: typ.type_field_iter()
            .map(|field| Field {
                name: field.name.to_string(),
                typ: field.typ.unresolved_type().to_string(),
                comment: meta.module
                    .get(AsRef::<str>::as_ref(&field.name))
                    .and_then(|meta| meta.comment.as_ref().map(|s| &s[..]))
                    .unwrap_or("")
                    .to_string(),
            })
            .collect(),

        values: typ.row_iter()
            .map(|field| Field {
                name: field.name.to_string(),
                typ: field.typ.to_string(),

                comment: meta.module
                    .get(AsRef::<str>::as_ref(&field.name))
                    .and_then(|meta| meta.comment.as_ref().map(|s| &s[..]))
                    .unwrap_or("")
                    .to_string(),
            })
            .collect(),
    }
}

#[derive(Serialize, Debug)]
pub struct TemplateModule<'a> {
    pub name: &'a str,
    pub record: &'a Record,
    pub sibling_modules: Vec<&'a str>,
}

pub fn generate<W>(reg: &Handlebars, out: &mut W, module: &TemplateModule) -> Result<()>
where
    W: io::Write,
{
    trace!("DOC: {:?}", module);

    let module_template = include_str!("doc/module.html");
    reg.render_template_to_write(module_template, &module, out)
        .with_context(|err| format!("Unable to render {}: {}", module.name, err))?;
    Ok(())
}

fn handlebars() -> Handlebars {
    let mut reg = Handlebars::new();

    fn symbol_link(
        h: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        let current_module = &rc.context().data()["name"]
            .as_str()
            .expect("name")
            .to_string();

        let param = String::deserialize(h.param(0).unwrap().value())?;
        write!(
            rc.writer,
            "{}{}.html",
            current_module.split('.').map(|_| "../").format(""),
            param.replace(".", "/")
        )?;
        Ok(())
    }
    reg.register_helper("symbol_link", Box::new(symbol_link));

    fn breadcrumbs(
        h: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        let param = String::deserialize(h.param(0).unwrap().value())?;
        let parts: Vec<_> = param.split(".").collect();
        for (i, part) in parts.iter().enumerate() {
            write!(
                rc.writer,
                r##"
{}
"##,
                if i + 1 == parts.len() { " active" } else { "" },
                if i + 1 == parts.len() {
                    handlebars::html_escape(&part)
                } else {
                    let path = (0..(parts.len() - i - 2)).map(|_| "../").format("");
                    format!(
                        r##"{}"##,
                        path,
                        handlebars::html_escape(&part)
                    )
                },
            )?;
        }
        Ok(())
    }
    reg.register_helper("breadcrumbs", Box::new(breadcrumbs));

    fn style(
        _: &Helper,
        _: &Handlebars,
        rc: &mut RenderContext,
    ) -> ::std::result::Result<(), RenderError> {
        write!(rc.writer, r#"
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
               "#)?;
        Ok(())
    }
    reg.register_helper("style", Box::new(style));

    reg
}

pub fn generate_for_path
(thread: &Thread, path: &P, out_path: &Q) -> Result<()>
where
    P: ?Sized + AsRef<Path>,
    Q: ?Sized + AsRef<Path>,
{
    generate_for_path_(thread, path.as_ref(), out_path.as_ref())
}

pub fn generate_for_path_(thread: &Thread, path: &Path, out_path: &Path) -> Result<()> {
    let reg = handlebars();
    let mut directories = Vec::new();
    for entry in walkdir::WalkDir::new(path) {
        let entry = entry?;
        if !entry.file_type().is_file()
            || entry.path().extension().and_then(|ext| ext.to_str()) != Some("glu")
        {
            if entry.file_type().is_dir() {
                directories.push((entry.path().to_owned(), Vec::new()));
            }
            continue;
        }
        let mut input = File::open(&*entry.path()).with_context(|err| {
            format!(
                "Unable to open gluon file `{}`: {}",
                entry.path().display(),
                err
            )
        })?;
        let mut content = String::new();
        input.read_to_string(&mut content)?;

        let name = filename_to_module(entry
            .path()
            .to_str()
            .ok_or_else(|| failure::err_msg("Non-UTF-8 filename"))?);

        let (expr, typ) = Compiler::new().typecheck_str(thread, &name, &content, None)?;
        let (meta, _) = metadata(&*thread.get_env(), &expr);

        create_dir_all(out_path.join(entry.path().parent().unwrap_or(Path::new(""))))?;

        let module = Module {
            name,
            record: record(&typ, &meta),
        };

        directories
            .last_mut()
            .expect("Directory before this file")
            .1
            .push(module);
    }

    #[derive(Serialize)]
    struct Index {
        name: String,
        modules: Vec<String>,
    }

    let module_template = include_str!("doc/index.html");

    for (path, modules) in directories {
        let index_path = out_path.join(&*path).join("index.html");
        trace!("Rendering index: {}", index_path.display());
        let mut doc_file = File::create(&*index_path).with_context(|err| {
            format!(
                "Unable to open output file `{}`: {}",
                index_path.display(),
                err
            )
        })?;

        for module in &modules {
            let out_path =
                out_path.join(PathBuf::from(module.name.replace(".", "/")).with_extension("html"));
            let mut doc_file = File::create(&*out_path).with_context(|err| {
                format!(
                    "Unable to open output file `{}`: {}",
                    out_path.display(),
                    err
                )
            })?;

            generate(
                &reg,
                &mut doc_file,
                &TemplateModule {
                    name: &module.name,
                    record: &module.record,
                    sibling_modules: modules.iter().map(|sibling| &*sibling.name).collect(),
                },
            )?;
        }

        let name = filename_to_module(path.to_str()
            .ok_or_else(|| failure::err_msg("Non-UTF-8 filename"))?);

        reg.render_template_to_write(
            module_template,
            &Index {
                name,
                modules: modules.iter().map(|module| module.name.clone()).collect(),
            },
            &mut doc_file,
        ).with_context(|err| {
            format!("Unable to render index {}: {}", index_path.display(), err)
        })?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use codec;
use futures::{stream, Stream};
use std::io;
use tokio_core::io::{Io, Framed};
use tokio_core::net::TcpStream;
use tokio_proto::pipeline::ServerProto;
use types::{GopherRequest, GopherResponse};

pub struct GopherServer;

impl ServerProto<TcpStream> for GopherServer {
    /// For this protocol style, `Request` matches the codec `In` type
    type Request = GopherRequest;

    /// For this protocol style, `Response` matches the coded `Out` type
    type Response = GopherResponse;

    /// A bit of boilerplate to hook in the codec:
    type Transport = stream::Take<Framed<TcpStream, codec::Server>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: TcpStream) -> Self::BindTransport {
        // Use .take() to close the stream after a single response.
        Ok(io.framed(codec::Server).take(1))
    }
}
<commit_msg>Make the protocol generic over Io<commit_after>use codec;
use futures::{stream, Stream};
use std::io;
use tokio_core::io::{Io, Framed};
use tokio_proto::pipeline::ServerProto;
use types::{GopherRequest, GopherResponse};

pub struct GopherServer;

impl<T: Io + 'static> ServerProto<T> for GopherServer {
    /// For this protocol style, `Request` matches the codec `In` type
    type Request = GopherRequest;

    /// For this protocol style, `Response` matches the coded `Out` type
    type Response = GopherResponse;

    /// A bit of boilerplate to hook in the codec:
    type Transport = stream::Take<Framed<T, codec::Server>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        // Use .take() to close the stream after a single response.
        Ok(io.framed(codec::Server).take(1))
    }
}
<|endoftext|>


<commit_before><commit_msg>First pass on eval() for states<commit_after><|endoftext|>


<commit_before>// xfail-stage0
// -*- rust -*-

use std;
import std._uint;

fn main() {
  check (_uint.next_power_of_two(0u) == 0u);
  check (_uint.next_power_of_two(1u) == 1u);
  check (_uint.next_power_of_two(2u) == 2u);
  check (_uint.next_power_of_two(3u) == 4u);
  check (_uint.next_power_of_two(4u) == 4u);
  check (_uint.next_power_of_two(5u) == 8u);
  check (_uint.next_power_of_two(6u) == 8u);
  check (_uint.next_power_of_two(7u) == 8u);
  check (_uint.next_power_of_two(8u) == 8u);
  check (_uint.next_power_of_two(9u) == 16u);
  check (_uint.next_power_of_two(10u) == 16u);
  check (_uint.next_power_of_two(11u) == 16u);
  check (_uint.next_power_of_two(12u) == 16u);
  check (_uint.next_power_of_two(13u) == 16u);
  check (_uint.next_power_of_two(14u) == 16u);
  check (_uint.next_power_of_two(15u) == 16u);
  check (_uint.next_power_of_two(16u) == 16u);
  check (_uint.next_power_of_two(17u) == 32u);
  check (_uint.next_power_of_two(18u) == 32u);
  check (_uint.next_power_of_two(19u) == 32u);
  check (_uint.next_power_of_two(20u) == 32u);
  check (_uint.next_power_of_two(21u) == 32u);
  check (_uint.next_power_of_two(22u) == 32u);
  check (_uint.next_power_of_two(23u) == 32u);
  check (_uint.next_power_of_two(24u) == 32u);
  check (_uint.next_power_of_two(25u) == 32u);
  check (_uint.next_power_of_two(26u) == 32u);
  check (_uint.next_power_of_two(27u) == 32u);
  check (_uint.next_power_of_two(28u) == 32u);
  check (_uint.next_power_of_two(29u) == 32u);
  check (_uint.next_power_of_two(30u) == 32u);
  check (_uint.next_power_of_two(31u) == 32u);
  check (_uint.next_power_of_two(32u) == 32u);
  check (_uint.next_power_of_two(33u) == 64u);
  check (_uint.next_power_of_two(34u) == 64u);
  check (_uint.next_power_of_two(35u) == 64u);
  check (_uint.next_power_of_two(36u) == 64u);
  check (_uint.next_power_of_two(37u) == 64u);
  check (_uint.next_power_of_two(38u) == 64u);
  check (_uint.next_power_of_two(39u) == 64u);
}
<commit_msg>rustc: Un-XFAIL lib-uint.rs<commit_after>// -*- rust -*-

use std;
import std._uint;

fn main() {
  check (_uint.next_power_of_two(0u) == 0u);
  check (_uint.next_power_of_two(1u) == 1u);
  check (_uint.next_power_of_two(2u) == 2u);
  check (_uint.next_power_of_two(3u) == 4u);
  check (_uint.next_power_of_two(4u) == 4u);
  check (_uint.next_power_of_two(5u) == 8u);
  check (_uint.next_power_of_two(6u) == 8u);
  check (_uint.next_power_of_two(7u) == 8u);
  check (_uint.next_power_of_two(8u) == 8u);
  check (_uint.next_power_of_two(9u) == 16u);
  check (_uint.next_power_of_two(10u) == 16u);
  check (_uint.next_power_of_two(11u) == 16u);
  check (_uint.next_power_of_two(12u) == 16u);
  check (_uint.next_power_of_two(13u) == 16u);
  check (_uint.next_power_of_two(14u) == 16u);
  check (_uint.next_power_of_two(15u) == 16u);
  check (_uint.next_power_of_two(16u) == 16u);
  check (_uint.next_power_of_two(17u) == 32u);
  check (_uint.next_power_of_two(18u) == 32u);
  check (_uint.next_power_of_two(19u) == 32u);
  check (_uint.next_power_of_two(20u) == 32u);
  check (_uint.next_power_of_two(21u) == 32u);
  check (_uint.next_power_of_two(22u) == 32u);
  check (_uint.next_power_of_two(23u) == 32u);
  check (_uint.next_power_of_two(24u) == 32u);
  check (_uint.next_power_of_two(25u) == 32u);
  check (_uint.next_power_of_two(26u) == 32u);
  check (_uint.next_power_of_two(27u) == 32u);
  check (_uint.next_power_of_two(28u) == 32u);
  check (_uint.next_power_of_two(29u) == 32u);
  check (_uint.next_power_of_two(30u) == 32u);
  check (_uint.next_power_of_two(31u) == 32u);
  check (_uint.next_power_of_two(32u) == 32u);
  check (_uint.next_power_of_two(33u) == 64u);
  check (_uint.next_power_of_two(34u) == 64u);
  check (_uint.next_power_of_two(35u) == 64u);
  check (_uint.next_power_of_two(36u) == 64u);
  check (_uint.next_power_of_two(37u) == 64u);
  check (_uint.next_power_of_two(38u) == 64u);
  check (_uint.next_power_of_two(39u) == 64u);
}
<|endoftext|>


<commit_before>use std::io::TcpStream;
use little_rust_tcp::data::Data;
use std::collections::ring_buf::RingBuf;
use std::sync::{Arc, Mutex};
use std::string::String;

pub struct DataStruct
{
    unprocessed_data: Arc<Mutex<RingBuf<String>>>,
    request_buffer: RingBuf<String>
}

pub trait DataConstructor
{
    fn new() -> DataStruct;
}

trait PrivateUtilityTrait
{

}

impl DataConstructor for DataStruct
{
    fn new() -> DataStruct
    {
        let unprocessed = Arc::new(Mutex::new(RingBuf::new()));
        let buffer = RingBuf::new();
        return DataStruct{unprocessed_data: unprocessed, request_buffer: buffer};
    }
}

impl Data for DataStruct
{
    fn process_request_data(&mut self, mut request: TcpStream)
    {
        let message = request.read_to_string();
        let someobject = message.ok();
        if (someobject != None)
        {
            let string = someobject.unwrap();
            if (string.len() > 0)
            {
                self.request_buffer.push_back(string);
                println!("{}", self.request_buffer.pop_front().unwrap());
            }
        }
        request.write(b"Hello World\r\n").unwrap();
    }
}
<commit_msg>Reduction<commit_after>use std::io::TcpStream;
use little_rust_tcp::data::Data;
use std::collections::ring_buf::RingBuf;
use std::sync::{Arc, Mutex};
use std::string::String;

pub struct DataStruct
{
    unprocessed_data: Arc<Mutex<RingBuf<String>>>,
    request_buffer: RingBuf<String>
}

pub trait DataConstructor
{
    fn new() -> DataStruct;
}

trait PrivateUtilityTrait
{

}

impl DataConstructor for DataStruct
{
    fn new() -> DataStruct
    {
        let unprocessed = Arc::new(Mutex::new(RingBuf::new()));
        let buffer = RingBuf::new();
        return DataStruct{unprocessed_data: unprocessed, request_buffer: buffer};
    }
}

impl Data for DataStruct
{
    fn process_request_data(&mut self, mut request: TcpStream)
    {
        let message = request.read_to_string();
        let someobject = message.ok();
        if (someobject != None)
        {
            let string = someobject.unwrap();
            if (string.len() > 0)
            {
                self.request_buffer.push_back(string);
            }
        }
        request.write(b"Hello World\r\n").unwrap();
    }
}
<|endoftext|>


<commit_before>//! Scheduling primitives for Uni.rs.

use alloc::boxed::{Box, FnBox};

use intrusive::link::Link;
use intrusive::list::{Node, Owner};

use self::stack::Stack;
use self::context::Context;

mod stack;
mod context;
mod scheduler;

const DEFAULT_STACK_SIZE: usize = 8192;

pub struct Thread {
    t_impl: Box<ThreadImpl>,
}

impl Thread {
    pub fn spawn<F>(fun: F) -> Thread where F: Fn() -> () {
        Builder::new().spawn(fun)
    }
}

pub struct Builder {
    stack_size: usize,
}

impl Builder {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn stack_size(mut self, stack_size: usize) -> Builder {
        self.stack_size = stack_size;
        self
    }

    pub fn spawn<F>(self, fun: F) -> Thread where F: Fn() -> () {
        let thread_impl = Box::new(ThreadImpl::new(fun, self.stack_size));

        Thread {
            t_impl: thread_impl,
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder {
            stack_size: DEFAULT_STACK_SIZE,
        }
    }
}

struct ThreadImpl {
    context: Context,
    // On Drop stack is released
    #[allow(dead_code)]
    stack: Stack,
    prev: Link<ThreadImpl>,
    next: Link<ThreadImpl>,
}

impl ThreadImpl {
    pub fn new<F>(fun: F, stack_size: usize) -> Self where F: Fn() -> () {
        let mut stack = unsafe { Stack::new(stack_size) };

        if stack.is_null() {
            panic!("Cannot allocate a stack (size: {}) for a new thread",
                   stack_size);
        }

        ThreadImpl {
            context: unsafe { Context::new(thread_wrapper, fun, &mut stack) },
            stack: stack,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

extern "C" fn thread_wrapper(f: *mut u8) -> ! {
    {
        let boxed_fn: Box<Box<FnBox()>> = unsafe {
            Box::from_raw(f as *mut Box<FnBox()>)
        };

        boxed_fn();
    }

    unimplemented!();
}

impl Node for ThreadImpl {
    #[inline]
    fn prev(&self) -> &Link<Self> {
        &self.prev
    }

    #[inline]
    fn next(&self) -> &Link<Self> {
        &self.next
    }

    #[inline]
    fn prev_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }

    #[inline]
    fn next_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }
}

// This trait cannot be implemented for Box in libintrusive as it must not
// depend on rust's liballoc
type ThreadImplBox = Box<ThreadImpl>;

impl Owner<ThreadImpl> for ThreadImplBox {
    #[inline]
    fn get(&self) -> &ThreadImpl {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut ThreadImpl {
        &mut **self
    }

    #[inline]
    fn take(self) {
        Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut ThreadImpl) -> Self {
        Box::from_raw(ptr)
    }
}
<commit_msg>thread: ThreadImpl now contains a state<commit_after>//! Scheduling primitives for Uni.rs.

use alloc::boxed::{Box, FnBox};

use intrusive::link::Link;
use intrusive::list::{Node, Owner};

use self::stack::Stack;
use self::context::Context;

mod stack;
mod context;
mod scheduler;

const DEFAULT_STACK_SIZE: usize = 8192;

pub struct Thread {
    t_impl: Box<ThreadImpl>,
}

impl Thread {
    pub fn spawn<F>(fun: F) -> Thread where F: Fn() -> () {
        Builder::new().spawn(fun)
    }
}

pub struct Builder {
    stack_size: usize,
}

impl Builder {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn stack_size(mut self, stack_size: usize) -> Builder {
        self.stack_size = stack_size;
        self
    }

    pub fn spawn<F>(self, fun: F) -> Thread where F: Fn() -> () {
        let thread_impl = Box::new(ThreadImpl::new(fun, self.stack_size));

        Thread {
            t_impl: thread_impl,
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder {
            stack_size: DEFAULT_STACK_SIZE,
        }
    }
}

#[derive(PartialEq)]
enum State {
    Empty,
    Ready,
    Running,
    Blocked,
    Terminated,
}

struct ThreadImpl {
    context: Context,
    state: State,
    // On Drop stack is released
    #[allow(dead_code)]
    stack: Stack,
    prev: Link<ThreadImpl>,
    next: Link<ThreadImpl>,
}

impl ThreadImpl {
    pub fn new<F>(fun: F, stack_size: usize) -> Self where F: Fn() -> () {
        let mut stack = unsafe { Stack::new(stack_size) };

        if stack.is_null() {
            panic!("Cannot allocate a stack (size: {}) for a new thread",
                   stack_size);
        }

        ThreadImpl {
            context: unsafe { Context::new(thread_wrapper, fun, &mut stack) },
            state: State::Ready,
            stack: stack,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

extern "C" fn thread_wrapper(f: *mut u8) -> ! {
    {
        let boxed_fn: Box<Box<FnBox()>> = unsafe {
            Box::from_raw(f as *mut Box<FnBox()>)
        };

        boxed_fn();
    }

    unimplemented!();
}

impl Node for ThreadImpl {
    #[inline]
    fn prev(&self) -> &Link<Self> {
        &self.prev
    }

    #[inline]
    fn next(&self) -> &Link<Self> {
        &self.next
    }

    #[inline]
    fn prev_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }

    #[inline]
    fn next_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }
}

// This trait cannot be implemented for Box in libintrusive as it must not
// depend on rust's liballoc
type ThreadImplBox = Box<ThreadImpl>;

impl Owner<ThreadImpl> for ThreadImplBox {
    #[inline]
    fn get(&self) -> &ThreadImpl {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut ThreadImpl {
        &mut **self
    }

    #[inline]
    fn take(self) {
        Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut ThreadImpl) -> Self {
        Box::from_raw(ptr)
    }
}
<|endoftext|>


<commit_before>use futures_util::future::{self, Either, FutureExt};
use std::collections::HashMap;
use std::hash::Hash;
use std::time::{Duration, Instant, SystemTime};
use tokio::sync::mpsc;
use tokio::time::{sleep_until, Duration as TokioDuration, Instant as TokioInstant};

/// Trait for converting various types to a timer deadline.
pub trait IntoDeadline {
    fn into_deadline(self) -> TokioInstant;
}

impl IntoDeadline for TokioInstant {
    fn into_deadline(self) -> TokioInstant {
        self
    }
}

impl IntoDeadline for Instant {
    fn into_deadline(self) -> TokioInstant {
        TokioInstant::from_std(self)
    }
}

impl IntoDeadline for Duration {
    fn into_deadline(self) -> TokioInstant {
        TokioInstant::now() + self
    }
}

impl IntoDeadline for SystemTime {
    fn into_deadline(self) -> TokioInstant {
        self.duration_since(SystemTime::now())
            .unwrap_or_default()
            .into_deadline()
    }
}

/// Task that runs a set of timers.
#[derive(Clone)]
pub struct DelayQueueTask<K: Clone + Eq + Hash + Send + 'static> {
    tx: mpsc::Sender<(K, TokioInstant)>,
}

impl<K: Clone + Eq + Hash + Send + 'static> DelayQueueTask<K> {
    /// Spawn a new task running a timer loop.
    ///
    /// The handler function is called when a timer expires with the timer key. Note that this
    /// function is called inside the Tokio run-time, and may not block.
    pub fn spawn<H>(mut handler: H) -> Self
    where
        H: (FnMut(K)) + Send + 'static,
    {
        let (tx, mut rx) = mpsc::channel(8);
        tokio::spawn(async move {
            // Arbitrary sleep duration to use while idle.
            let idle_wait = TokioDuration::new(86400 * 365, 0);
            let mut deadline = TokioInstant::now() + idle_wait;
            let mut items = HashMap::<K, TokioInstant>::new();
            loop {
                let recv = rx.recv().fuse();
                let sleep = sleep_until(deadline).fuse();
                tokio::pin!(recv, sleep);
                match future::select(recv, sleep).await {
                    Either::Left((Some((key, item_deadline)), _)) => {
                        items.insert(key, deadline);
                        if item_deadline < deadline {
                            deadline = item_deadline;
                        }
                    }
                    Either::Left((None, _)) => break,
                    Either::Right(_) => {
                        let now = TokioInstant::now();
                        let mut expired_key = None;
                        deadline = now + idle_wait;
                        for (key, item_deadline) in &items {
                            if expired_key.is_none() && *item_deadline <= now {
                                expired_key = Some(key.clone());
                            } else if *item_deadline < deadline {
                                deadline = *item_deadline;
                            }
                        }
                        if let Some(key) = expired_key {
                            items.remove(&key);
                            handler(key);
                        }
                    }
                }
            }
        });
        DelayQueueTask { tx }
    }

    /// Insert or replace a timer.
    pub async fn insert(&mut self, key: K, deadline: impl IntoDeadline) {
        let deadline = deadline.into_deadline();
        if self.tx.send((key, deadline)).await.is_err() {
            panic!("Tried to send to DelayQueueTask that has panicked");
        }
    }
}
<commit_msg>Fix broken key rotation<commit_after>use futures_util::future::{self, Either, FutureExt};
use std::collections::HashMap;
use std::hash::Hash;
use std::time::{Duration, SystemTime};
use tokio::sync::mpsc;
use tokio::time::{sleep_until, Duration as TokioDuration, Instant as TokioInstant};

/// Trait for converting various types to a timer deadline.
pub trait IntoDeadline {
    fn into_deadline(self) -> TokioInstant;
}

impl IntoDeadline for TokioInstant {
    fn into_deadline(self) -> TokioInstant {
        self
    }
}

impl IntoDeadline for Duration {
    fn into_deadline(self) -> TokioInstant {
        TokioInstant::now() + self
    }
}

impl IntoDeadline for SystemTime {
    fn into_deadline(self) -> TokioInstant {
        self.duration_since(SystemTime::now())
            .unwrap_or_default()
            .into_deadline()
    }
}

/// Task that runs a set of timers.
#[derive(Clone)]
pub struct DelayQueueTask<K: Clone + Eq + Hash + Send + 'static> {
    tx: mpsc::Sender<(K, TokioInstant)>,
}

impl<K: Clone + Eq + Hash + Send + 'static> DelayQueueTask<K> {
    /// Spawn a new task running a timer loop.
    ///
    /// The handler function is called when a timer expires with the timer key. Note that this
    /// function is called inside the Tokio run-time, and may not block.
    pub fn spawn<H>(mut handler: H) -> Self
    where
        H: (FnMut(K)) + Send + 'static,
    {
        let (tx, mut rx) = mpsc::channel(8);
        tokio::spawn(async move {
            // Arbitrary sleep duration to use while idle.
            let idle_wait = TokioDuration::new(86400 * 365, 0);
            let mut deadline = TokioInstant::now() + idle_wait;
            let mut items = HashMap::<K, TokioInstant>::new();
            loop {
                let recv = rx.recv().fuse();
                let sleep = sleep_until(deadline).fuse();
                tokio::pin!(recv, sleep);
                match future::select(recv, sleep).await {
                    Either::Left((Some((key, item_deadline)), _)) => {
                        items.insert(key, item_deadline);
                        if item_deadline < deadline {
                            deadline = item_deadline;
                        }
                    }
                    Either::Left((None, _)) => break,
                    Either::Right(_) => {
                        let now = TokioInstant::now();
                        let mut expired_key = None;
                        deadline = now + idle_wait;
                        for (key, item_deadline) in &items {
                            if expired_key.is_none() && *item_deadline <= now {
                                expired_key = Some(key.clone());
                            } else if *item_deadline < deadline {
                                deadline = *item_deadline;
                            }
                        }
                        if let Some(key) = expired_key {
                            items.remove(&key);
                            handler(key);
                        }
                    }
                }
            }
        });
        DelayQueueTask { tx }
    }

    /// Insert or replace a timer.
    pub async fn insert(&mut self, key: K, deadline: impl IntoDeadline) {
        let deadline = deadline.into_deadline();
        if self.tx.send((key, deadline)).await.is_err() {
            panic!("Tried to send to DelayQueueTask that has panicked");
        }
    }
}
<|endoftext|>


<commit_before>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Broadcast packet types.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

// Game state changes
const GAMEEXITED : u16 = 2;

// Opcode info
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcasted game name
const HALO_RETAIL : &'static str = "halor";

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::sync::{Arc, Mutex};

extern crate time;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::HeartbeatPacket;

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = match UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)) {
        Err(error) => {
            println!("Error creating a UDP socket at {}:{}. {}.",ip,BROADCAST_PORT_UDP,error);
            return;
        },
        Ok(halo_socket) => halo_socket
    };

    let client_socket = match TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)) {
        Err(error) => {
            println!("Error listening to TCP at {}:{}. {}.",ip,SERVER_LIST_PORT_TCP,error);
            return;
        },
        Ok(client_socket) => client_socket
    };

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    thread::spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = time::now().to_timespec().sec;
            servers.retain(|x| x.last_alive + DROP_TIME > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Vec<String> = Vec::new();
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    thread::spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).
                    unwrap_or_else(|_| Vec::new());
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    thread::spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = match stream {
                    Err(_) => continue,
                    Ok(the_stream) => the_stream
                };
                // Unwrap the IP.
                let ip = match client.peer_addr() {
                    Err(_) => continue,
                    Ok(ip) => ip.ip_string()
                };

                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    // These are the allowed game versions. HaloMD and Halo PC 1.09 uses 01.00.09.0620, while Halo PC servers on 1.10 use 01.00.10.0621 (these are also joinable).
    let game_versions = [ "01.00.09.0620".to_string(), "01.00.10.0621".to_string() ];

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = match halo_socket.recv_from(&mut buffer) {
            Err(_) => continue,
            Ok(x) => x
        };
        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if blacklist_ref.contains(&client_ip) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = time::now().to_timespec().sec;
                    match servers.iter_mut().position(|x| x.ip == client_ip && x.port == packet.localport) {
                        None => {
                            if game_versions.contains(&packet.gamever) && &packet.gamename == HALO_RETAIL {
                                let serverness = HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime };
                                (*servers).push(serverness);
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if i.ip == client_ip && i.port == source.port() {
                    i.last_alive = time::now().to_timespec().sec;
                    break;
                }
            }
        }
    }
}
<commit_msg>Blacklist doesn't have to exist at all<commit_after>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Broadcast packet types.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

// Game state changes
const GAMEEXITED : u16 = 2;

// Opcode info
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcasted game name
const HALO_RETAIL : &'static str = "halor";

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::sync::{Arc, Mutex};

extern crate time;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::HeartbeatPacket;

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = match UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)) {
        Err(error) => {
            println!("Error creating a UDP socket at {}:{}. {}.",ip,BROADCAST_PORT_UDP,error);
            return;
        },
        Ok(halo_socket) => halo_socket
    };

    let client_socket = match TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)) {
        Err(error) => {
            println!("Error listening to TCP at {}:{}. {}.",ip,SERVER_LIST_PORT_TCP,error);
            return;
        },
        Ok(client_socket) => client_socket
    };

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    thread::spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = time::now().to_timespec().sec;
            servers.retain(|x| x.last_alive + DROP_TIME > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Option<Vec<String>> = None;
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    thread::spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).ok();
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    thread::spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = match stream {
                    Err(_) => continue,
                    Ok(the_stream) => the_stream
                };
                // Unwrap the IP.
                let ip = match client.peer_addr() {
                    Err(_) => continue,
                    Ok(ip) => ip.ip_string()
                };

                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    // These are the allowed game versions. HaloMD and Halo PC 1.09 uses 01.00.09.0620, while Halo PC servers on 1.10 use 01.00.10.0621 (these are also joinable).
    let game_versions = [ "01.00.09.0620".to_string(), "01.00.10.0621".to_string() ];

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = match halo_socket.recv_from(&mut buffer) {
            Err(_) => continue,
            Ok(x) => x
        };
        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        let in_blacklist = match *blacklist_ref {
            Some(ref blacklist) => blacklist.contains(&client_ip),
            None => false
        };
        if in_blacklist {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = time::now().to_timespec().sec;
                    match servers.iter_mut().position(|x| x.ip == client_ip && x.port == packet.localport) {
                        None => {
                            if game_versions.contains(&packet.gamever) && &packet.gamename == HALO_RETAIL {
                                let serverness = HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime };
                                (*servers).push(serverness);
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if i.ip == client_ip && i.port == source.port() {
                    i.last_alive = time::now().to_timespec().sec;
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;

use std::thread;

use piston_window::*;

fn main() {
    let handle = thread::spawn(move || {
        let mut window: PistonWindow = WindowSettings::new(
            "Hello Piston!", [800, 600]
        ).exit_on_esc(true).build().unwrap();
        while let Some(e) = window.next() {
            window.draw_2d(&e, |c, g| {
                clear([1.0; 4], g);

                let center = (200., 200.);
                let radius = 100.;
                let thickness = 1.;
                let mut prev = (center.0 + radius, center.0);
                for i in 0..361 {
                    let x = center.0 + radius * (i as f64).to_radians().cos();
                    let y = center.1 + radius * (i as f64).to_radians().sin();
                    line([0., 0., 0., 255.], thickness, [prev.0, prev.1, x, y], c.transform, g);
                    prev = (x, y);
                }
                line([0., 0., 0., 255.], 1., [250., 150., 400., 300.], c.transform, g);
                line([0., 0., 0., 255.], 1., [550., 150., 350., 500.], c.transform, g);
            });
        }
    });

    handle.join().unwrap();
}
<commit_msg>Prototyping thread communication<commit_after>extern crate piston_window;

use std::thread;
use std::sync::mpsc::{self, TryRecvError};

use piston_window::*;

enum Shape {
    Line {
        from: (f64, f64),
        to: (f64, f64),
        thickness: f64,
    },
}

enum Response {
    Ok,
}

fn main() {
    let (tx_drawing, rx_drawing) = mpsc::channel();
    let (tx_main, rx_main) = mpsc::channel();

    thread::spawn(move || {
        let mut window: PistonWindow = WindowSettings::new(
            "Hello Piston!", [800, 600]
        ).exit_on_esc(true).build().unwrap();
        let mut shapes = vec![];

        while let Some(e) = window.next() {
            match rx_drawing.try_recv() {
                Ok(shape) => {
                    shapes.push(shape);
                    tx_main.send(Response::Ok).unwrap();
                },
                Err(TryRecvError::Empty) => {}, // Do nothing
                Err(TryRecvError::Disconnected) => break, // Quit
            }

            window.draw_2d(&e, |c, g| {
                clear([1.0; 4], g);

                for shape in &shapes {
                    match shape {
                        &Shape::Line {from, to, thickness} => {
                            line([0., 0., 0., 255.], thickness,
                                [from.0, from.1, to.0, to.1], c.transform, g);
                        },
                    }
                }
            });
        }
    });

    //TODO: Instead of unwrapping, we should quit since this means that the drawing
    //TODO: window has been closed (possibly due to an error on that thread)
    let draw = |shape: Shape| {
        tx_drawing.send(shape).unwrap();
        rx_main.recv().unwrap();
    };

    let center = (200., 200.);
    let radius = 100.;
    let thickness = 1.;
    let mut prev = (center.0 + radius, center.0);
    for i in 0..361 {
        let x = center.0 + radius * (i as f64).to_radians().cos();
        let y = center.1 + radius * (i as f64).to_radians().sin();
        draw(Shape::Line {
            from: (prev.0, prev.1),
            to: (x, y),
            thickness,
        });
        prev = (x, y);
    }
    draw(Shape::Line {
        from: (550., 150.),
        to: (350., 500.),
        thickness,
    });
    //handle.join().unwrap();
}
<|endoftext|>


<commit_before>extern crate rust_fluent;
use rust_fluent::tcp;

use std::collections::HashMap;

fn main() {
    let mut obj: HashMap<String, String> = HashMap::new();
    obj.insert("key".to_string(), "value".to_string());

    let fluentd = tcp::Fluentd::new("0.0.0.0:24224","foo");

    let _ = fluentd.write(&obj);
}
<commit_msg>remove blank line<commit_after>extern crate rust_fluent;
use rust_fluent::tcp;

use std::collections::HashMap;

fn main() {
    let mut obj: HashMap<String, String> = HashMap::new();
    obj.insert("key".to_string(), "value".to_string());

    let fluentd = tcp::Fluentd::new("0.0.0.0:24224","foo");

    let _ = fluentd.write(&obj);
}
<|endoftext|>