<commit_before>use std::io;
use std::error::Error;
use std::fmt;

use libradium::Frontend;
use mio_channel::Receiver;
use mio::{Poll, Token, Ready, PollOpt, Events, Event};
use mio::unix::UnixReady;
use radium_protocol::{Message, ReadValueExt, WriteValueExt, WatchMode, ReadError, WriteError, ErrorCode};
use radium_protocol::messages::{EntryExpired, ErrorMessage};

use super::actions::Action;
use super::connection::{Connection, Connections, Added, Rejected};
use super::entry::{Entry, EntryData};

pub const MESSAGE_TOKEN: Token = Token(10_000_000);
pub const DEFAULT_WORKER_CONNECTIONS: usize = 128;

pub enum WorkerMessage {
    Connection(Connection),
    Push(Entry)
}

#[derive(Debug)]
pub enum WorkerError {
    ReadError(ReadError),
    WriteError(WriteError),
    IoError(io::Error)
}

type WorkerResult<T> = Result<T, WorkerError>;

pub struct Worker {
    id: usize,
    connections: Connections,
    poll: Poll,
    receiver: Receiver<WorkerMessage>,
    frontend: Frontend<EntryData>,
}

impl fmt::Display for WorkerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for WorkerError {
    fn description(&self) -> &str {
        match self {
            &WorkerError::ReadError(ref err) => err.description(),
            &WorkerError::WriteError(ref err) => err.description(),
            &WorkerError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &WorkerError::ReadError(ref err) => err.cause(),
            &WorkerError::WriteError(ref err) => err.cause(),
            &WorkerError::IoError(ref err) => err.cause(),
        }
    }
}

impl From<io::Error> for WorkerError {
    fn from(err: io::Error) -> Self {
        WorkerError::IoError(err)
    }
}

impl From<ReadError> for WorkerError {
    fn from(err: ReadError) -> Self {
        WorkerError::ReadError(err)
    }
}

impl From<WriteError> for WorkerError {
    fn from(err: WriteError) -> Self {
        WorkerError::WriteError(err)
    }
}

impl Worker {
    pub fn new(id: usize, poll: Poll, receiver: Receiver<WorkerMessage>, frontend: Frontend<EntryData>) -> Self {
        let connections = env_var!("RADIUM_WORKER_CONNECTIONS", DEFAULT_WORKER_CONNECTIONS);

        Worker {
            id,
            connections: Connections::with_capacity(connections),
            poll,
            receiver,
            frontend,
        }
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);

        loop {
            self.poll.poll(&mut events, None).unwrap();

            for i in 0..events.len() {
                let event = events.get(i).unwrap();

                self.handle_event(event);
            }
        }
    }

    fn handle_event(&mut self, event: Event) {
        let token = event.token();
        let ready = event.readiness();
        let unix_ready = UnixReady::from(ready);

        if unix_ready.is_hup() || unix_ready.is_error() {
            self.disconnect(token, None).unwrap();
            return;
        }

        if token == MESSAGE_TOKEN {
            let msg = self.receiver.try_recv().unwrap();

            return match msg {
                WorkerMessage::Connection(conn) => { self.accept(conn) }
                WorkerMessage::Push(entry) => { self.push(entry) }
            }
        }

        if let Err(..) = self.handle_msg(token) {
            self.disconnect(token, Some(ErrorCode::ConnectionFailure)).unwrap();
        }
    }

    fn handle_msg(&mut self, token: Token) -> WorkerResult<()> {
        if let Some(conn) = self.connections.get_conn_mut(token) {
            let msg: Message = conn.read_value::<Message>()?;

            let msg_type = msg.message_type();

            let resp: Message = match msg.process(conn, &mut self.frontend) {
                Ok(resp) => { resp }
                Err(err) => { err.into() }
            };

            debug!("worker {}, conn {} | {:?} -> {:?}", self.id, token.0, msg_type, resp.message_type());

            conn.write_value(&resp)?;
        }

        Ok(())
    }

    fn accept(&mut self, conn: Connection) {
        let result = match self.connections.add_conn(conn) {
            Added(conn_ref, token) => {
                self.poll.register(conn_ref, token, Ready::readable(), PollOpt::edge())
            }
            Rejected(conn) => { conn.close() }
        };

        // TODO: idk what to do with this result
        result.unwrap();
    }

    fn push(&mut self, entry: Entry) {
        let id = entry.id();
        let inner = EntryExpired::new(id.timestamp(), id.id(), entry.consume_data());
        let msg = Message::EntryExpired(inner);

        for conn in self.connections.iter_mut() {
            if conn.watch_mode() == WatchMode::None {
                continue;
            }

            // TODO: error handling
            let _ = conn.write_value(&msg);
        }
    }

    fn disconnect(&mut self, token: Token, code: Option<ErrorCode>) -> WorkerResult<()> {
        let conn = self.connections.remove_conn(token);

        match conn {
            Some(mut conn) => {
                self.poll.deregister(&conn)?;

                // We're intentionally ignoring the result here
                // don't need the guarantee that the error code has come through
                if let Some(code) = code {
                    let _ = conn.write_value(&ErrorMessage::new(code));
                }

                Ok(())
            }
            None => { Ok(()) }
        }
    }
}<commit_msg>Correct import<commit_after>use std::io;
use std::error::Error;
use std::fmt;

use libradium::Frontend;
use mio_channel::Receiver;
use mio::{Poll, Token, Ready, PollOpt, Events, Event};
use mio::unix::UnixReady;
use radium_protocol::{Message, ReadValueExt, WriteValueExt, WatchMode, ErrorCode};
use radium_protocol::errors::{ReadError, WriteError};
use radium_protocol::messages::{EntryExpired, ErrorMessage};

use super::actions::Action;
use super::connection::{Connection, Connections, Added, Rejected};
use super::entry::{Entry, EntryData};

pub const MESSAGE_TOKEN: Token = Token(10_000_000);
pub const DEFAULT_WORKER_CONNECTIONS: usize = 128;

pub enum WorkerMessage {
    Connection(Connection),
    Push(Entry)
}

#[derive(Debug)]
pub enum WorkerError {
    ReadError(ReadError),
    WriteError(WriteError),
    IoError(io::Error)
}

type WorkerResult<T> = Result<T, WorkerError>;

pub struct Worker {
    id: usize,
    connections: Connections,
    poll: Poll,
    receiver: Receiver<WorkerMessage>,
    frontend: Frontend<EntryData>,
}

impl fmt::Display for WorkerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for WorkerError {
    fn description(&self) -> &str {
        match self {
            &WorkerError::ReadError(ref err) => err.description(),
            &WorkerError::WriteError(ref err) => err.description(),
            &WorkerError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &WorkerError::ReadError(ref err) => err.cause(),
            &WorkerError::WriteError(ref err) => err.cause(),
            &WorkerError::IoError(ref err) => err.cause(),
        }
    }
}

impl From<io::Error> for WorkerError {
    fn from(err: io::Error) -> Self {
        WorkerError::IoError(err)
    }
}

impl From<ReadError> for WorkerError {
    fn from(err: ReadError) -> Self {
        WorkerError::ReadError(err)
    }
}

impl From<WriteError> for WorkerError {
    fn from(err: WriteError) -> Self {
        WorkerError::WriteError(err)
    }
}

impl Worker {
    pub fn new(id: usize, poll: Poll, receiver: Receiver<WorkerMessage>, frontend: Frontend<EntryData>) -> Self {
        let connections = env_var!("RADIUM_WORKER_CONNECTIONS", DEFAULT_WORKER_CONNECTIONS);

        Worker {
            id,
            connections: Connections::with_capacity(connections),
            poll,
            receiver,
            frontend,
        }
    }

    pub fn run(&mut self) {
        let mut events = Events::with_capacity(1024);

        loop {
            self.poll.poll(&mut events, None).unwrap();

            for i in 0..events.len() {
                let event = events.get(i).unwrap();

                self.handle_event(event);
            }
        }
    }

    fn handle_event(&mut self, event: Event) {
        let token = event.token();
        let ready = event.readiness();
        let unix_ready = UnixReady::from(ready);

        if unix_ready.is_hup() || unix_ready.is_error() {
            self.disconnect(token, None).unwrap();
            return;
        }

        if token == MESSAGE_TOKEN {
            let msg = self.receiver.try_recv().unwrap();

            return match msg {
                WorkerMessage::Connection(conn) => { self.accept(conn) }
                WorkerMessage::Push(entry) => { self.push(entry) }
            }
        }

        if let Err(..) = self.handle_msg(token) {
            self.disconnect(token, Some(ErrorCode::ConnectionFailure)).unwrap();
        }
    }

    fn handle_msg(&mut self, token: Token) -> WorkerResult<()> {
        if let Some(conn) = self.connections.get_conn_mut(token) {
            let msg: Message = conn.read_value::<Message>()?;

            let msg_type = msg.message_type();

            let resp: Message = match msg.process(conn, &mut self.frontend) {
                Ok(resp) => { resp }
                Err(err) => { err.into() }
            };

            debug!("worker {}, conn {} | {:?} -> {:?}", self.id, token.0, msg_type, resp.message_type());

            conn.write_value(&resp)?;
        }

        Ok(())
    }

    fn accept(&mut self, conn: Connection) {
        let result = match self.connections.add_conn(conn) {
            Added(conn_ref, token) => {
                self.poll.register(conn_ref, token, Ready::readable(), PollOpt::edge())
            }
            Rejected(conn) => { conn.close() }
        };

        // TODO: idk what to do with this result
        result.unwrap();
    }

    fn push(&mut self, entry: Entry) {
        let id = entry.id();
        let inner = EntryExpired::new(id.timestamp(), id.id(), entry.consume_data());
        let msg = Message::EntryExpired(inner);

        for conn in self.connections.iter_mut() {
            if conn.watch_mode() == WatchMode::None {
                continue;
            }

            // TODO: error handling
            let _ = conn.write_value(&msg);
        }
    }

    fn disconnect(&mut self, token: Token, code: Option<ErrorCode>) -> WorkerResult<()> {
        let conn = self.connections.remove_conn(token);

        match conn {
            Some(mut conn) => {
                self.poll.deregister(&conn)?;

                // We're intentionally ignoring the result here
                // don't need the guarantee that the error code has come through
                if let Some(code) = code {
                    let _ = conn.write_value(&ErrorMessage::new(code));
                }

                Ok(())
            }
            None => { Ok(()) }
        }
    }
}<|endoftext|>


<commit_before>use light::Light;
use raytracer::compositor::{ColorRGBA, Surface, SurfaceFactory};
use raytracer::{Intersection, Ray};
use scene::{Camera, Scene};
use std::ops::Deref;
use std::sync::Arc;
use std::sync::mpsc::channel;
use vec3::Vec3;
use rand::{thread_rng, Rng, Isaac64Rng};
use threadpool::ThreadPool;

pub static EPSILON: f64 = ::std::f64::EPSILON * 10000.0;

#[derive(Clone, Copy)]
pub struct RenderOptions {
    pub reflect_depth: u32,  // Maximum reflection recursions.
    pub refract_depth: u32,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub shadow_samples: u32, // Number of samples for soft shadows and area lights.
    pub gloss_samples: u32,  // Number of samples for glossy reflections.
    pub pixel_samples: u32,  // The square of this is the number of samples per pixel.
}

#[derive(Clone)]
pub struct Renderer {
    pub tasks: usize, // Minimum number of tasks to spawn.
    pub options: RenderOptions,
}

impl Renderer {
    pub fn render(&self, camera: Camera, shared_scene: Arc<Scene>) -> Surface {

        let mut surface = Surface::new(camera.image_width as usize,
                                       camera.image_height as usize,
                                       ColorRGBA::new_rgb(0, 0, 0));

        let pool = ThreadPool::new(self.tasks);

        let (tx, rx) = channel();

        let mut jobs = 0;

        for subsurface_factory in surface.divide(128, 8) {
            jobs += 1;

            let renderer = self.clone();
            let child_tx = tx.clone();
            let scene_local = shared_scene.clone();
            let camera_local = camera.clone();

            pool.execute(move || {
                let _ = child_tx.send(renderer.render_tile(camera_local.clone(),
                    scene_local.deref(), subsurface_factory));
            });
        }
        drop(tx);

        let start_time = ::time::get_time();

        for (i, subsurface) in rx.iter().enumerate() {
            surface.merge(&subsurface);
            ::util::print_progress("Tile", start_time.clone(), (i + 1) as usize, jobs);
        }
        surface
    }

    fn render_tile(&self, camera: Camera, scene: &Scene, tile_factory: SurfaceFactory) -> Surface {
        let mut tile = tile_factory.create();
        let mut rng: Isaac64Rng = thread_rng().gen();
        let pixel_samples = self.options.pixel_samples;

        for rel_y in 0usize..tile.height {
            let abs_y = camera.image_height as usize - (tile.y_off + rel_y) - 1;
            for rel_x in 0usize..tile.width {
                let abs_x = tile.x_off + rel_x;

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;
                let mut color = Vec3::zero();

                for y_subpixel in 0u32..pixel_samples {
                    for x_subpixel in 0u32..pixel_samples {
                        // Don't jitter if not antialiasing
                        let (j_x, j_y) = if pixel_samples > 1 {
                            (x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width,
                             y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width)
                        } else {
                            (0.0, 0.0)
                        };

                        let ray = camera.get_ray(abs_x as f64 + j_x, abs_y as f64 + j_y);
                        let result = Renderer::trace(scene, &ray, self.options, false);
                        // Clamp subpixels for now to avoid intense aliasing when combined value is clamped later
                        // Should think of a better way to handle this
                        color = color + result.clamp(0.0, 1.0).scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }
                tile[(rel_x, rel_y)] = ColorRGBA::new_rgb_clamped(color.x, color.y, color.z);
            }
        }

        tile
    }

    fn trace(scene: &Scene, ray: &Ray, options: RenderOptions, inside: bool) -> Vec3 {
        if options.reflect_depth <= 0 || options.refract_depth <= 0 { return Vec3::zero() }

        match ray.get_nearest_hit(scene) {
            Some(hit) => {
                let n = hit.n.unit();
                let i = (-ray.direction).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let shadow = Renderer::shadow_intensity(scene, &hit, light, options.shadow_samples);
                    let l = (light.center() - hit.position).unit();

                    color_acc + light.color() * hit.material.sample(n, i, l, hit.u, hit.v) * shadow
                });

                // Global lighting computation: reflections, refractions
                if hit.material.is_reflective() || hit.material.is_refractive() {
                    let reflect_fresnel = Renderer::fresnel_reflect(hit.material.ior(), &i, &n, inside);
                    let refract_fresnel = 1.0 - reflect_fresnel;

                    if hit.material.is_reflective() {
                        result = result + Renderer::global_reflection(scene, &hit, options, inside,
                                                                      &i, &n, reflect_fresnel);
                    }

                    if hit.material.is_refractive() {
                        result = result + Renderer::global_transmission(scene, &hit, options, inside,
                                                                        &i, &n, refract_fresnel);
                    }
                }

                result
            },
            None => {
                match scene.skybox {
                    Some(ref skybox) => skybox.color(ray.direction),
                    None => scene.background
                }
            }
        }
    }

    fn global_reflection(scene: &Scene, hit: &Intersection, options: RenderOptions, inside: bool,
                         i: &Vec3, n: &Vec3, reflect_fresnel: f64) -> Vec3 {

        let r = Vec3::reflect(&i, &n);
        let reflect_ray = Ray::new(hit.position, r);
        let next_reflect_options = RenderOptions { reflect_depth: options.reflect_depth - 1, ..options };

        let reflection = if hit.material.is_glossy() {
            // For glossy materials, average multiple perturbed reflection rays
            // Potential overflow by scaling after everything is done instead of scaling every iteration?
            (0..options.gloss_samples).fold(Vec3::zero(), |acc, _| {
                let gloss_reflect_ray = reflect_ray.perturb(hit.material.glossiness());
                acc + Renderer::trace(scene, &gloss_reflect_ray, next_reflect_options, inside)
            }).scale(1.0 / options.gloss_samples as f64)
        } else {
            // For mirror-like materials just shoot a perfectly reflected ray instead
            Renderer::trace(scene, &reflect_ray, next_reflect_options, inside)
        };

        hit.material.global_specular(&reflection).scale(reflect_fresnel)
    }

    fn global_transmission(scene: &Scene, hit: &Intersection, options: RenderOptions, inside: bool,
                           i: &Vec3, n: &Vec3, refract_fresnel: f64) -> Vec3 {

        let (t, actual_refract_fresnel) = match Vec3::refract(&i, &n, hit.material.ior(), inside) {
            Some(ref t) => (*t, refract_fresnel),
            None => {
                (Vec3::reflect(&i, &n), 1.0) // Fresnel of 1.0 = total internal reflection (TODO: verify)
            }
        };

        // Offset ray origin by EPSILON * direction to avoid hitting self when refracting
        let refract_ray = Ray::new(hit.position + t.scale(EPSILON), t);
        let next_refract_options = RenderOptions { refract_depth: options.refract_depth - 1, ..options };
        let refraction = Renderer::trace(scene, &refract_ray, next_refract_options, !inside);

        hit.material.global_transmissive(&refraction).scale(actual_refract_fresnel)
    }

    fn shadow_intensity(scene: &Scene, hit: &Intersection,
                        light: &Box<Light+Send+Sync>, shadow_samples: u32) -> Vec3 {

        if shadow_samples <= 0 { return Vec3::one() }

        // Point light speedup (no point in sampling a point light multiple times)
        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };
        let mut shadow = Vec3::zero();

        // Take average shadow color after jittering/sampling light position
        for _ in 0..shadow_sample_tries {
            // L has to be a unit vector for t_max 1:1 correspondence to
            // distance to light to work. Shadow feelers only search up
            // until light source.
            let sampled_light_position = light.position();
            let shadow_l = (sampled_light_position - hit.position).unit();
            let shadow_ray = Ray::new(hit.position, shadow_l);
            let distance_to_light = (sampled_light_position - hit.position).len();

            // Check against candidate primitives in scene for occlusion
            // and multiply shadow color by occluders' shadow colors
            let candidate_nodes = scene.octree.intersect_iter(&shadow_ray);

            shadow = shadow + candidate_nodes.fold(Vec3::one(), |shadow_acc, prim| {
                let occlusion = prim.intersects(&shadow_ray, EPSILON, distance_to_light);
                match occlusion {
                    Some(occlusion) => shadow_acc * occlusion.material.transmission(),
                    None => shadow_acc
                }
            });
        }

        shadow.scale(1.0 / shadow_sample_tries as f64)
    }

    /// Calculates the fresnel (reflectivity) given the index of refraction and the cos_angle
    /// This uses Schlick's approximation. cos_angle is normal_dot_incoming
    /// http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
    fn fresnel_reflect(ior: f64, i: &Vec3, n: &Vec3, inside: bool) -> f64 {
        let (n1, n2) = if inside { (ior, 1.0) } else { (1.0, ior) };
        let actual_n = if inside { -*n } else { *n };

        let r0_sqrt = (n1 - n2) / (n1 + n2);
        let r0 = r0_sqrt * r0_sqrt;

        let cos_angle = if n1 <= n2 {
            i.dot(&actual_n)
        } else {
            let t = match Vec3::refract(i, &-actual_n, ior, inside) {
                Some(x) => x,
                None => return 1.0 // n1 > n2 && TIR
            };

            -actual_n.dot(&t) // n1 > n2 && !TIR
        };

        let cos_term = 1.0 - cos_angle;

        (r0 + ((1.0 - r0) * cos_term * cos_term * cos_term * cos_term * cos_term)).max(0.0).min(1.0)
    }
}

#[test]
fn it_renders_the_background_of_an_empty_scene() {
    let camera = Camera::new(
        Vec3 { x: 0.0, y: 0.0, z: 0.0 },
        Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        45.0,
        32,
        32
    );

    let test_scene = Scene {
        lights: vec!(),
        octree: vec!().into_iter().collect(),
        background: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        skybox: None
    };

    let shared_scene = Arc::new(test_scene);

    let render_options = RenderOptions {
        reflect_depth: 1,
        refract_depth: 1,
        shadow_samples: 1,
        gloss_samples: 1,
        pixel_samples: 1,
    };

    let renderer = Renderer {
        options: render_options,
        tasks: 2,
    };

    let image_data = renderer.render(camera, shared_scene);

    for color in image_data.buffer.iter() {
        assert_eq!(color.r, 255);
        assert_eq!(color.g, 0);
        assert_eq!(color.b, 0);
    }
}
<commit_msg>Make Renderer::render_tile static<commit_after>use light::Light;
use raytracer::compositor::{ColorRGBA, Surface, SurfaceFactory};
use raytracer::{Intersection, Ray};
use scene::{Camera, Scene};
use std::ops::Deref;
use std::sync::Arc;
use std::sync::mpsc::channel;
use vec3::Vec3;
use rand::{thread_rng, Rng, Isaac64Rng};
use threadpool::ThreadPool;

pub static EPSILON: f64 = ::std::f64::EPSILON * 10000.0;

#[derive(Clone, Copy)]
pub struct RenderOptions {
    pub reflect_depth: u32,  // Maximum reflection recursions.
    pub refract_depth: u32,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub shadow_samples: u32, // Number of samples for soft shadows and area lights.
    pub gloss_samples: u32,  // Number of samples for glossy reflections.
    pub pixel_samples: u32,  // The square of this is the number of samples per pixel.
}

#[derive(Clone)]
pub struct Renderer {
    pub tasks: usize, // Minimum number of tasks to spawn.
    pub options: RenderOptions,
}

impl Renderer {
    pub fn render(&self, camera: Camera, shared_scene: Arc<Scene>) -> Surface {

        let mut surface = Surface::new(camera.image_width as usize,
                                       camera.image_height as usize,
                                       ColorRGBA::new_rgb(0, 0, 0));

        let pool = ThreadPool::new(self.tasks);

        let (tx, rx) = channel();

        let mut jobs = 0;

        for subsurface_factory in surface.divide(128, 8) {
            jobs += 1;

            let renderer_opts = self.options.clone();
            let child_tx = tx.clone();
            let scene_local = shared_scene.clone();
            let camera_local = camera.clone();

            pool.execute(move || {
                let scene = scene_local.deref();
                let _ = child_tx.send(Renderer::render_tile(camera_local, scene,
                    renderer_opts, subsurface_factory)).unwrap();
            });
        }
        drop(tx);

        let start_time = ::time::get_time();

        for (i, subsurface) in rx.iter().enumerate() {
            surface.merge(&subsurface);
            ::util::print_progress("Tile", start_time.clone(), (i + 1) as usize, jobs);
        }
        surface
    }

    fn render_tile(camera: Camera, scene: &Scene, options: RenderOptions, tile_factory: SurfaceFactory) -> Surface {
        let mut tile = tile_factory.create();
        let mut rng: Isaac64Rng = thread_rng().gen();
        let pixel_samples = options.pixel_samples;

        for rel_y in 0usize..tile.height {
            let abs_y = camera.image_height as usize - (tile.y_off + rel_y) - 1;
            for rel_x in 0usize..tile.width {
                let abs_x = tile.x_off + rel_x;

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;
                let mut color = Vec3::zero();

                for y_subpixel in 0u32..pixel_samples {
                    for x_subpixel in 0u32..pixel_samples {
                        // Don't jitter if not antialiasing
                        let (j_x, j_y) = if pixel_samples > 1 {
                            (x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width,
                             y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width)
                        } else {
                            (0.0, 0.0)
                        };

                        let ray = camera.get_ray(abs_x as f64 + j_x, abs_y as f64 + j_y);
                        let result = Renderer::trace(scene, &ray, options, false);
                        // Clamp subpixels for now to avoid intense aliasing when combined value is clamped later
                        // Should think of a better way to handle this
                        color = color + result.clamp(0.0, 1.0).scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }
                tile[(rel_x, rel_y)] = ColorRGBA::new_rgb_clamped(color.x, color.y, color.z);
            }
        }

        tile
    }

    fn trace(scene: &Scene, ray: &Ray, options: RenderOptions, inside: bool) -> Vec3 {
        if options.reflect_depth <= 0 || options.refract_depth <= 0 { return Vec3::zero() }

        match ray.get_nearest_hit(scene) {
            Some(hit) => {
                let n = hit.n.unit();
                let i = (-ray.direction).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let shadow = Renderer::shadow_intensity(scene, &hit, light, options.shadow_samples);
                    let l = (light.center() - hit.position).unit();

                    color_acc + light.color() * hit.material.sample(n, i, l, hit.u, hit.v) * shadow
                });

                // Global lighting computation: reflections, refractions
                if hit.material.is_reflective() || hit.material.is_refractive() {
                    let reflect_fresnel = Renderer::fresnel_reflect(hit.material.ior(), &i, &n, inside);
                    let refract_fresnel = 1.0 - reflect_fresnel;

                    if hit.material.is_reflective() {
                        result = result + Renderer::global_reflection(scene, &hit, options, inside,
                                                                      &i, &n, reflect_fresnel);
                    }

                    if hit.material.is_refractive() {
                        result = result + Renderer::global_transmission(scene, &hit, options, inside,
                                                                        &i, &n, refract_fresnel);
                    }
                }

                result
            },
            None => {
                match scene.skybox {
                    Some(ref skybox) => skybox.color(ray.direction),
                    None => scene.background
                }
            }
        }
    }

    fn global_reflection(scene: &Scene, hit: &Intersection, options: RenderOptions, inside: bool,
                         i: &Vec3, n: &Vec3, reflect_fresnel: f64) -> Vec3 {

        let r = Vec3::reflect(&i, &n);
        let reflect_ray = Ray::new(hit.position, r);
        let next_reflect_options = RenderOptions { reflect_depth: options.reflect_depth - 1, ..options };

        let reflection = if hit.material.is_glossy() {
            // For glossy materials, average multiple perturbed reflection rays
            // Potential overflow by scaling after everything is done instead of scaling every iteration?
            (0..options.gloss_samples).fold(Vec3::zero(), |acc, _| {
                let gloss_reflect_ray = reflect_ray.perturb(hit.material.glossiness());
                acc + Renderer::trace(scene, &gloss_reflect_ray, next_reflect_options, inside)
            }).scale(1.0 / options.gloss_samples as f64)
        } else {
            // For mirror-like materials just shoot a perfectly reflected ray instead
            Renderer::trace(scene, &reflect_ray, next_reflect_options, inside)
        };

        hit.material.global_specular(&reflection).scale(reflect_fresnel)
    }

    fn global_transmission(scene: &Scene, hit: &Intersection, options: RenderOptions, inside: bool,
                           i: &Vec3, n: &Vec3, refract_fresnel: f64) -> Vec3 {

        let (t, actual_refract_fresnel) = match Vec3::refract(&i, &n, hit.material.ior(), inside) {
            Some(ref t) => (*t, refract_fresnel),
            None => {
                (Vec3::reflect(&i, &n), 1.0) // Fresnel of 1.0 = total internal reflection (TODO: verify)
            }
        };

        // Offset ray origin by EPSILON * direction to avoid hitting self when refracting
        let refract_ray = Ray::new(hit.position + t.scale(EPSILON), t);
        let next_refract_options = RenderOptions { refract_depth: options.refract_depth - 1, ..options };
        let refraction = Renderer::trace(scene, &refract_ray, next_refract_options, !inside);

        hit.material.global_transmissive(&refraction).scale(actual_refract_fresnel)
    }

    fn shadow_intensity(scene: &Scene, hit: &Intersection,
                        light: &Box<Light+Send+Sync>, shadow_samples: u32) -> Vec3 {

        if shadow_samples <= 0 { return Vec3::one() }

        // Point light speedup (no point in sampling a point light multiple times)
        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };
        let mut shadow = Vec3::zero();

        // Take average shadow color after jittering/sampling light position
        for _ in 0..shadow_sample_tries {
            // L has to be a unit vector for t_max 1:1 correspondence to
            // distance to light to work. Shadow feelers only search up
            // until light source.
            let sampled_light_position = light.position();
            let shadow_l = (sampled_light_position - hit.position).unit();
            let shadow_ray = Ray::new(hit.position, shadow_l);
            let distance_to_light = (sampled_light_position - hit.position).len();

            // Check against candidate primitives in scene for occlusion
            // and multiply shadow color by occluders' shadow colors
            let candidate_nodes = scene.octree.intersect_iter(&shadow_ray);

            shadow = shadow + candidate_nodes.fold(Vec3::one(), |shadow_acc, prim| {
                let occlusion = prim.intersects(&shadow_ray, EPSILON, distance_to_light);
                match occlusion {
                    Some(occlusion) => shadow_acc * occlusion.material.transmission(),
                    None => shadow_acc
                }
            });
        }

        shadow.scale(1.0 / shadow_sample_tries as f64)
    }

    /// Calculates the fresnel (reflectivity) given the index of refraction and the cos_angle
    /// This uses Schlick's approximation. cos_angle is normal_dot_incoming
    /// http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
    fn fresnel_reflect(ior: f64, i: &Vec3, n: &Vec3, inside: bool) -> f64 {
        let (n1, n2) = if inside { (ior, 1.0) } else { (1.0, ior) };
        let actual_n = if inside { -*n } else { *n };

        let r0_sqrt = (n1 - n2) / (n1 + n2);
        let r0 = r0_sqrt * r0_sqrt;

        let cos_angle = if n1 <= n2 {
            i.dot(&actual_n)
        } else {
            let t = match Vec3::refract(i, &-actual_n, ior, inside) {
                Some(x) => x,
                None => return 1.0 // n1 > n2 && TIR
            };

            -actual_n.dot(&t) // n1 > n2 && !TIR
        };

        let cos_term = 1.0 - cos_angle;

        (r0 + ((1.0 - r0) * cos_term * cos_term * cos_term * cos_term * cos_term)).max(0.0).min(1.0)
    }
}

#[test]
fn it_renders_the_background_of_an_empty_scene() {
    let camera = Camera::new(
        Vec3 { x: 0.0, y: 0.0, z: 0.0 },
        Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        45.0,
        32,
        32
    );

    let test_scene = Scene {
        lights: vec!(),
        octree: vec!().into_iter().collect(),
        background: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        skybox: None
    };

    let shared_scene = Arc::new(test_scene);

    let render_options = RenderOptions {
        reflect_depth: 1,
        refract_depth: 1,
        shadow_samples: 1,
        gloss_samples: 1,
        pixel_samples: 1,
    };

    let renderer = Renderer {
        options: render_options,
        tasks: 2,
    };

    let image_data = renderer.render(camera, shared_scene);

    for color in image_data.buffer.iter() {
        assert_eq!(color.r, 255);
        assert_eq!(color.g, 0);
        assert_eq!(color.b, 0);
    }
}
<|endoftext|>


<commit_before>
extern crate clap;
extern crate itertools;
extern crate num_integer;
extern crate regex;

// Time Start: Thu, 12 Dec 2019 12:27:13 -0500
// Time Finish 1: Thu, 12 Dec 2019 15:55:35 -0500 (3 hours, 28 minutes, 22 seconds)
// Time Finish 2: Thu, 12 Dec 2019 16:56:18 -0500 (1 hour, 0 minutes, 43 seconds)
// Time Total: 4 hours, 29 minutes, 5 seconds

use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt;
use std::fs;
use std::str::FromStr;

use clap::{Arg, App};
use itertools::Itertools;
use num_integer::Integer;
use regex::Regex;

struct Moon {
    pub pos: [i32; 3],
    pub vel: [i32; 3],
}
impl Moon {
    pub fn parse(line: &String) -> Moon {
        // <x=-8, y=-18, z=6>  :: Blah, too lazy to fix the unwraps.
        let re = Regex::new(r"^<x=([-\d]+), y=([-\d]+), z=([-\d]+)>").unwrap_or_else(|err| panic!("regex error: {}", err));
        if let Some(cap) = re.captures(line) {
            let pos: Vec<i32> = cap.iter().skip(1).map(|c| c.unwrap().as_str().parse::<i32>().unwrap()).collect();
            return Moon {
                pos: [ pos[0], pos[1], pos[2] ],
                vel: [ 0, 0, 0 ],
            }
        }
        panic!("Invalid input: {}", line);
    }

    pub fn gravitate(&mut self, other: &Moon) {
        for i in 0..3 {
            self.vel[i] += match self.pos[i].cmp(&other.pos[i]) {
                Ordering::Less => 1,
                Ordering::Greater => -1,
                Ordering::Equal => 0,
            };
        }
    }

    pub fn step(&mut self) {
        for i in 0..3 {
            self.pos[i] += self.vel[i];
        }
    }

    pub fn energy(&self) -> i32 {
        let potential = self.pos.iter().map(|v| v.abs()).fold(0_i32, |a, b| a.checked_add(b).unwrap_or_else(|| panic!("Numeric overflow in potential energy")));
        let kinetic   = self.vel.iter().map(|v| v.abs()).fold(0_i32, |a, b| a.checked_add(b).unwrap_or_else(|| panic!("Numeric overflow in kinetic energy")));
        return potential * kinetic;
    }
}
impl fmt::Display for Moon {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "pos=<x={}, y={}, z={}>, vel=<x={}, y={}, z={}>", self.pos[0], self.pos[1], self.pos[2], self.vel[0], self.vel[1], self.vel[2])
    }
}
impl FromStr for Moon {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Moon::parse(&String::from(s)))
    }
}

fn step(moons: &mut Vec<Moon>) {
    // This is stupid!
    for pair in (0..moons.len()).combinations(2) { // .combinations() Clones iterator elements
        let (i, j) = if pair[0] < pair[1] { (pair[0], pair[1]) } else { (pair[1], pair[0]) }; // Probably ordered but just in case
        let (a, b) = moons.split_at_mut(j); // WTF Rust!
        a[i].gravitate(&b[0]);
        b[0].gravitate(&a[i]);
    }
    for m in moons.iter_mut() {
        m.step();
    }
}

fn fingerprint(i: usize, moons: &Vec<Moon>) -> Vec<i32> {
    let mut v = Vec::new();
    for m in moons {
        v.push(m.pos[i]);
        v.push(m.vel[i]);
    }
    return v;
}

fn periods(mut moons: &mut Vec<Moon>) -> Vec<u64> {
    let mut done   = vec![false, false, false];
    let mut period = vec![0, 0, 0];
    let mut seen   = vec![HashSet::new(), HashSet::new(), HashSet::new()];

    loop {
        let mut todo = false;
        for i in 0..3 {
            if !done[i] {
                let fprint = fingerprint(i, moons);
                if seen[i].insert(fprint) {
                    period[i] += 1;
                    todo = true;
                } else {
                    done[i] = true;
                    println!("Axis {} has period {}", i, period[i]);
                }
            }
        }
        if !todo { break; }
        step(&mut moons);
    }
    return period;
}

fn load_moons(fname: &String) -> Vec<Moon> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

    return contents.trim().split('\n').map(|l| { l.parse::<Moon>().unwrap_or_else(|err| panic!("Bummer: {}", err)) }).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 12")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("12.in"));

    // Step 1
    let num_iter = 1000;
    let mut moons = load_moons(&fname);
    for _ in 1..=num_iter { step(&mut moons); }

    let mut energy = 0;
    for m in &moons {
        println!("{}  : energy {}", m, m.energy());
        energy += m.energy();
    }
    println!("Total energy after {} steps: {}\n", num_iter, energy);

    // Step 2
    let mut moons = load_moons(&fname);
    let periods = periods(&mut moons);
    println!("Period of whole system: {}", periods.iter().fold(1, |a, b| a.lcm(b)));
}
<commit_msg>More comments on split_at_mut() use<commit_after>
extern crate clap;
extern crate itertools;
extern crate num_integer;
extern crate regex;

// Time Start: Thu, 12 Dec 2019 12:27:13 -0500
// Time Finish 1: Thu, 12 Dec 2019 15:55:35 -0500 (3 hours, 28 minutes, 22 seconds)
// Time Finish 2: Thu, 12 Dec 2019 16:56:18 -0500 (1 hour, 0 minutes, 43 seconds)
// Time Total: 4 hours, 29 minutes, 5 seconds

use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt;
use std::fs;
use std::str::FromStr;

use clap::{Arg, App};
use itertools::Itertools;
use num_integer::Integer;
use regex::Regex;

struct Moon {
    pub pos: [i32; 3],
    pub vel: [i32; 3],
}
impl Moon {
    pub fn parse(line: &String) -> Moon {
        // <x=-8, y=-18, z=6>  :: Blah, too lazy to fix the unwraps.
        let re = Regex::new(r"^<x=([-\d]+), y=([-\d]+), z=([-\d]+)>").unwrap_or_else(|err| panic!("regex error: {}", err));
        if let Some(cap) = re.captures(line) {
            let pos: Vec<i32> = cap.iter().skip(1).map(|c| c.unwrap().as_str().parse::<i32>().unwrap()).collect();
            return Moon {
                pos: [ pos[0], pos[1], pos[2] ],
                vel: [ 0, 0, 0 ],
            }
        }
        panic!("Invalid input: {}", line);
    }

    pub fn gravitate(&mut self, other: &Moon) {
        for i in 0..3 {
            self.vel[i] += match self.pos[i].cmp(&other.pos[i]) {
                Ordering::Less => 1,
                Ordering::Greater => -1,
                Ordering::Equal => 0,
            };
        }
    }

    pub fn step(&mut self) {
        for i in 0..3 {
            self.pos[i] += self.vel[i];
        }
    }

    pub fn energy(&self) -> i32 {
        let potential = self.pos.iter().map(|v| v.abs()).fold(0_i32, |a, b| a.checked_add(b).unwrap_or_else(|| panic!("Numeric overflow in potential energy")));
        let kinetic   = self.vel.iter().map(|v| v.abs()).fold(0_i32, |a, b| a.checked_add(b).unwrap_or_else(|| panic!("Numeric overflow in kinetic energy")));
        return potential * kinetic;
    }
}
impl fmt::Display for Moon {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "pos=<x={}, y={}, z={}>, vel=<x={}, y={}, z={}>", self.pos[0], self.pos[1], self.pos[2], self.vel[0], self.vel[1], self.vel[2])
    }
}
impl FromStr for Moon {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Moon::parse(&String::from(s)))
    }
}

fn step(moons: &mut Vec<Moon>) {
    // This is stupid!
    //
    // Our gravitate() requires self to be mutable but its argyment to be
    // non-mutable. Rust apparently locks the whole vec as mut/non-mut
    // which prevents us from simultaneously doing a = vec.get(i), b =
    // vec.get_mut(j). If we access the elements through a slice, however,
    // rust can lock each slice separately, hence the song and dance here.
    for pair in (0..moons.len()).combinations(2) { // .combinations() Clones iterator elements
        let (i, j) = if pair[0] < pair[1] { (pair[0], pair[1]) } else { (pair[1], pair[0]) }; // Probably ordered but just in case
        let (a, b) = moons.split_at_mut(j); // WTF Rust!
        a[i].gravitate(&b[0]);
        b[0].gravitate(&a[i]);
    }
    for m in moons.iter_mut() {
        m.step();
    }
}

fn fingerprint(i: usize, moons: &Vec<Moon>) -> Vec<i32> {
    let mut v = Vec::new();
    for m in moons {
        v.push(m.pos[i]);
        v.push(m.vel[i]);
    }
    return v;
}

fn periods(mut moons: &mut Vec<Moon>) -> Vec<u64> {
    let mut done   = vec![false, false, false];
    let mut period = vec![0, 0, 0];
    let mut seen   = vec![HashSet::new(), HashSet::new(), HashSet::new()];

    loop {
        let mut todo = false;
        for i in 0..3 {
            if !done[i] {
                let fprint = fingerprint(i, moons);
                if seen[i].insert(fprint) {
                    period[i] += 1;
                    todo = true;
                } else {
                    done[i] = true;
                    println!("Axis {} has period {}", i, period[i]);
                }
            }
        }
        if !todo { break; }
        step(&mut moons);
    }
    return period;
}

fn load_moons(fname: &String) -> Vec<Moon> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

    return contents.trim().split('\n').map(|l| { l.parse::<Moon>().unwrap_or_else(|err| panic!("Bummer: {}", err)) }).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 12")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("12.in"));

    // Step 1
    let num_iter = 1000;
    let mut moons = load_moons(&fname);
    for _ in 1..=num_iter { step(&mut moons); }

    let mut energy = 0;
    for m in &moons {
        println!("{}  : energy {}", m, m.energy());
        energy += m.energy();
    }
    println!("Total energy after {} steps: {}\n", num_iter, energy);

    // Step 2
    let mut moons = load_moons(&fname);
    let periods = periods(&mut moons);
    println!("Period of whole system: {}", periods.iter().fold(1, |a, b| a.lcm(b)));
}
<|endoftext|>


<commit_before>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice};
use glow::HasContext;
use hal::{image, window as w};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let client_extensions =
            egl::query_string(None, egl::EXTENSIONS).map_err(|_| hal::UnsupportedBackend)?;
        log::info!("Client extensions: {:?}", client_extensions);

        //TODO: requre  `GL_OES_surfaceless_context` or work around it

        #[cfg(feature = "x11")]
        let display = {
            const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
            let x11_display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
            assert!(!x11_display.is_null());
            let display_attributes = [egl::ATTRIB_NONE];
            egl::get_platform_display(
                EGL_PLATFORM_X11_KHR,
                x11_display as *mut _,
                &display_attributes,
            )
            .unwrap()
        };
        #[cfg(not(feature = "x11"))]
        let display = egl::get_display(egl::DEFAULT_DISPLAY).unwrap();

        let version = egl::initialize(display).map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl::query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl::query_string(Some(display), egl::EXTENSIONS).unwrap();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        assert!(version >= (1, 4), "Unable to request GL context");

        {
            debug!("Configurations:");
            let config_count = egl::get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl::get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                debug!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl::get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl::get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl::get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl::get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let config = match egl::choose_first_config(display, &config_attributes) {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl::choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl::bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let gles_version = (3, 1);
        let mut context_attributes = vec![
            egl::CONTEXT_MAJOR_VERSION,
            gles_version.0,
            egl::CONTEXT_MINOR_VERSION,
            gles_version.1,
        ];
        if cfg!(debug_assertions) {
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl::create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES {:?} context: {:?}", gles_version, e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            display,
            version,
            config,
            context,
            supports_native_window,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();
        let gl = unsafe {
            GlContainer::from_fn_proc(|name| egl::get_proc_address(name).unwrap() as *const _)
        };

        // Create physical device
        vec![PhysicalDevice::new_adapter(gl)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match egl::create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        egl::destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = egl::destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = egl::terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image = native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        egl::make_current(
            self.display,
            Some(self.raw),
            Some(self.raw),
            Some(self.context),
        )
        .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        egl::swap_buffers(self.display, self.raw).unwrap();
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();

        Ok(None)
    }
}
<commit_msg>Support xcb window handles in egl create_surface<commit_after>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice};
use glow::HasContext;
use hal::{image, window as w};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let client_extensions =
            egl::query_string(None, egl::EXTENSIONS).map_err(|_| hal::UnsupportedBackend)?;
        log::info!("Client extensions: {:?}", client_extensions);

        //TODO: requre  `GL_OES_surfaceless_context` or work around it

        #[cfg(feature = "x11")]
        let display = {
            const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
            let x11_display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
            assert!(!x11_display.is_null());
            let display_attributes = [egl::ATTRIB_NONE];
            egl::get_platform_display(
                EGL_PLATFORM_X11_KHR,
                x11_display as *mut _,
                &display_attributes,
            )
            .unwrap()
        };
        #[cfg(not(feature = "x11"))]
        let display = egl::get_display(egl::DEFAULT_DISPLAY).unwrap();

        let version = egl::initialize(display).map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl::query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl::query_string(Some(display), egl::EXTENSIONS).unwrap();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        assert!(version >= (1, 4), "Unable to request GL context");

        {
            debug!("Configurations:");
            let config_count = egl::get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl::get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                debug!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl::get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl::get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl::get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl::get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let config = match egl::choose_first_config(display, &config_attributes) {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl::choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl::bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let gles_version = (3, 1);
        let mut context_attributes = vec![
            egl::CONTEXT_MAJOR_VERSION,
            gles_version.0,
            egl::CONTEXT_MINOR_VERSION,
            gles_version.1,
        ];
        if cfg!(debug_assertions) {
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl::create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES {:?} context: {:?}", gles_version, e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            display,
            version,
            config,
            context,
            supports_native_window,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();
        let gl = unsafe {
            GlContainer::from_fn_proc(|name| egl::get_proc_address(name).unwrap() as *const _)
        };

        // Create physical device
        vec![PhysicalDevice::new_adapter(gl)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(not(target_os = "android"))]
            Rwh::Xcb(handle) => handle.window as _,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match egl::create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        egl::destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = egl::destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = egl::terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image = native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        egl::make_current(
            self.display,
            Some(self.raw),
            Some(self.raw),
            Some(self.context),
        )
        .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        egl::swap_buffers(self.display, self.raw).unwrap();
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();

        Ok(None)
    }
}
<|endoftext|>


<commit_before>//! A collection of named color constants. Can be toggled with the `"named"` and
//! `"named_from_str"` Cargo features.
//!
//! They are taken from the [SVG keyword
//! colors](https://www.w3.org/TR/SVG/types.html#ColorKeywords) (same as in
//! CSS3) and they can be used as if they were pixel values:
//!
//! ```
//! use palette::Srgb;
//! use palette::named;
//!
//! //From constant
//! let from_const = Srgb::<f32>::from_format(named::OLIVE).into_linear();
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "//From name string")]
#![cfg_attr(feature = "named_from_str", doc = "let olive = named::from_str(\"olive\").expect(\"unknown color\");")]
#![cfg_attr(feature = "named_from_str", doc = "let from_str = Srgb::<f32>::from_format(olive).into_linear();")]
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "assert_eq!(from_const, from_str);")]
//! ```

include!(concat!(env!("OUT_DIR"), "/named.rs"));

/// Get a SVG/CSS3 color by name. Can be toggled with the `"named_from_str"`
/// Cargo feature.
///
/// The names are the same as the constants, but lower case.
#[cfg(feature = "named_from_str")]
pub fn from_str(name: &str) -> Option<crate::Srgb<u8>> {
    COLORS.get(name).cloned()
}
<commit_msg>fixed broken link to SVG colornames<commit_after>//! A collection of named color constants. Can be toggled with the `"named"` and
//! `"named_from_str"` Cargo features.
//!
//! They are taken from the [SVG keyword
//! colors](https://www.w3.org/TR/SVG11/types.html#ColorKeywords) (same as in
//! CSS3) and they can be used as if they were pixel values:
//!
//! ```
//! use palette::Srgb;
//! use palette::named;
//!
//! //From constant
//! let from_const = Srgb::<f32>::from_format(named::OLIVE).into_linear();
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "//From name string")]
#![cfg_attr(feature = "named_from_str", doc = "let olive = named::from_str(\"olive\").expect(\"unknown color\");")]
#![cfg_attr(feature = "named_from_str", doc = "let from_str = Srgb::<f32>::from_format(olive).into_linear();")]
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "assert_eq!(from_const, from_str);")]
//! ```

include!(concat!(env!("OUT_DIR"), "/named.rs"));

/// Get a SVG/CSS3 color by name. Can be toggled with the `"named_from_str"`
/// Cargo feature.
///
/// The names are the same as the constants, but lower case.
#[cfg(feature = "named_from_str")]
pub fn from_str(name: &str) -> Option<crate::Srgb<u8>> {
    COLORS.get(name).cloned()
}
<|endoftext|>


<commit_before>use compositor::Server;
use wlroots::{key_events::KeyEvent,
              xkbcommon::xkb::{KEY_Escape, KEY_F1, KEY_Super_L, KEY_Super_R}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED};
pub struct Keyboard;

fn key_is_meta(key: u32) -> bool {
    // TODO configure meta key
    key == KEY_Super_L || key == KEY_Super_R
}

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle, event: &KeyEvent) {
        with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                        // TODO Remove
                    } else if key == KEY_F1 {
                        ::std::thread::spawn(|| {
                            ::std::process::Command::new("weston-terminal").output()
                                .unwrap()
                        });
                    }
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = true;
                    }
                }
            } else {
                for key in event.pressed_keys() {
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = false;
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
                seat.keyboard_send_modifiers(&mut keyboard.get_modifier_masks());
            }).expect("Seat was destroyed");
        }).unwrap();
    }
}
<commit_msg>handle keyboard modifiers<commit_after>use compositor::Server;
use wlroots::{key_events::KeyEvent,
              xkbcommon::xkb::{KEY_Escape, KEY_F1, KEY_Super_L, KEY_Super_R}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED};
pub struct Keyboard;

fn key_is_meta(key: u32) -> bool {
    // TODO configure meta key
    key == KEY_Super_L || key == KEY_Super_R
}

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self,
              compositor: CompositorHandle,
              _keyboard: KeyboardHandle,
              event: &KeyEvent) {
        with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                        // TODO Remove
                    } else if key == KEY_F1 {
                        ::std::thread::spawn(|| {
                            ::std::process::Command::new("weston-terminal").output()
                                .unwrap()
                        });
                    }
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = true;
                    }
                }
            } else {
                for key in event.pressed_keys() {
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = false;
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
            }).expect("Seat was destroyed");
        }).unwrap();
    }

    fn modifiers(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_modifiers(&mut keyboard.get_modifier_masks());
            }).unwrap();
        }).unwrap();
    }
}
<|endoftext|>


<commit_before>use super::{
    super::job::{RefinedJob, TeeItem},
    PipelineError,
};

use nix::{fcntl::OFlag, unistd};
use std::{fs::File, os::unix::io::FromRawFd};

pub fn create_pipe() -> Result<(File, File), PipelineError> {
    let (reader, writer) =
        unistd::pipe2(OFlag::O_CLOEXEC).map_err(PipelineError::CreatePipeError)?;
    Ok(unsafe { (File::from_raw_fd(reader), File::from_raw_fd(writer)) })
}

pub struct TeePipe<'a, 'b> {
    parent:          &'a mut RefinedJob<'b>,
    ext_stdio_pipes: &'a mut Option<Vec<File>>,
    is_external:     bool,
}

impl<'a, 'b> TeePipe<'a, 'b> {
    pub fn new(
        parent: &'a mut RefinedJob<'b>,
        ext_stdio_pipes: &'a mut Option<Vec<File>>,
        is_external: bool,
    ) -> Self {
        TeePipe { parent, ext_stdio_pipes, is_external }
    }

    fn inner_connect<F>(&mut self, tee: &mut TeeItem, mut action: F) -> Result<(), PipelineError>
    where
        F: FnMut(&mut RefinedJob<'b>, File),
    {
        let (reader, writer) = create_pipe()?;
        (*tee).source = Some(reader);
        if self.is_external {
            self.ext_stdio_pipes
                .get_or_insert_with(|| Vec::with_capacity(4))
                .push(writer.try_clone().map_err(PipelineError::ClonePipeFailed)?);
        }
        action(self.parent, writer);
        Ok(())
    }

    pub fn connect(&mut self, out: &mut TeeItem, err: &mut TeeItem) -> Result<(), PipelineError> {
        self.inner_connect(out, RefinedJob::stdout)?;
        self.inner_connect(err, RefinedJob::stderr)
    }
}
<commit_msg>fix: Split pipe2 into pipe and fcntl on macOS and iOS<commit_after>use super::{
    super::job::{RefinedJob, TeeItem},
    PipelineError,
};

#[cfg(any(target_os = "ios", target_os = "macos"))]
use nix::fcntl::{fcntl, FcntlArg};
use nix::{fcntl::OFlag, unistd};
use std::{fs::File, os::unix::io::FromRawFd};

#[cfg(not(any(target_os = "ios", target_os = "macos")))]
pub fn create_pipe() -> Result<(File, File), PipelineError> {
    let (reader, writer) =
        unistd::pipe2(OFlag::O_CLOEXEC).map_err(PipelineError::CreatePipeError)?;
    Ok(unsafe { (File::from_raw_fd(reader), File::from_raw_fd(writer)) })
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub fn create_pipe() -> Result<(File, File), PipelineError> {
    let (reader, writer) = unistd::pipe().map_err(PipelineError::CreatePipeError)?;
    fcntl(reader, FcntlArg::F_SETFL(OFlag::O_CLOEXEC)).map_err(PipelineError::CreatePipeError)?;
    fcntl(writer, FcntlArg::F_SETFL(OFlag::O_CLOEXEC)).map_err(PipelineError::CreatePipeError)?;
    Ok(unsafe { (File::from_raw_fd(reader), File::from_raw_fd(writer)) })
}

pub struct TeePipe<'a, 'b> {
    parent:          &'a mut RefinedJob<'b>,
    ext_stdio_pipes: &'a mut Option<Vec<File>>,
    is_external:     bool,
}

impl<'a, 'b> TeePipe<'a, 'b> {
    pub fn new(
        parent: &'a mut RefinedJob<'b>,
        ext_stdio_pipes: &'a mut Option<Vec<File>>,
        is_external: bool,
    ) -> Self {
        TeePipe { parent, ext_stdio_pipes, is_external }
    }

    fn inner_connect<F>(&mut self, tee: &mut TeeItem, mut action: F) -> Result<(), PipelineError>
    where
        F: FnMut(&mut RefinedJob<'b>, File),
    {
        let (reader, writer) = create_pipe()?;
        (*tee).source = Some(reader);
        if self.is_external {
            self.ext_stdio_pipes
                .get_or_insert_with(|| Vec::with_capacity(4))
                .push(writer.try_clone().map_err(PipelineError::ClonePipeFailed)?);
        }
        action(self.parent, writer);
        Ok(())
    }

    pub fn connect(&mut self, out: &mut TeeItem, err: &mut TeeItem) -> Result<(), PipelineError> {
        self.inner_connect(out, RefinedJob::stdout)?;
        self.inner_connect(err, RefinedJob::stderr)
    }
}
<|endoftext|>


<commit_before>use rustc::ty;
use rustc_ast::ast::{self, MetaItem};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_span::symbol::{sym, Symbol};

pub(crate) use self::drop_flag_effects::*;
pub use self::impls::borrows::Borrows;
pub use self::impls::DefinitelyInitializedPlaces;
pub use self::impls::EverInitializedPlaces;
pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive};

use self::move_paths::MoveData;

pub mod drop_flag_effects;
pub mod generic;
mod impls;
pub mod move_paths;

pub(crate) mod indexes {
    pub(crate) use super::{
        impls::borrows::BorrowIndex,
        move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
    };
}

pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
    for attr in attrs {
        if attr.check_name(sym::rustc_mir) {
            let items = attr.meta_item_list();
            for item in items.iter().flat_map(|l| l.iter()) {
                match item.meta_item() {
                    Some(mi) if mi.check_name(name) => return Some(mi.clone()),
                    _ => continue,
                }
            }
        }
    }
    None
}

pub struct MoveDataParamEnv<'tcx> {
    pub(crate) move_data: MoveData<'tcx>,
    pub(crate) param_env: ty::ParamEnv<'tcx>,
}

/// Parameterization for the precise form of data flow that is used.
///
/// `BottomValue` determines whether the initial entry set for each basic block is empty or full.
/// This also determines the semantics of the lattice `join` operator used to merge dataflow
/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed
/// point.
///
/// This means, for propagation across the graph, that you either want to start at all-zeroes and
/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect
/// as your merge when propagating.
pub trait BottomValue {
    /// Specifies the initial value for each bit in the entry set for each basic block.
    const BOTTOM_VALUE: bool;

    /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed.
    ///
    /// It is almost certainly wrong to override this, since it automatically applies
    /// * `inout_set & in_set` if `BOTTOM_VALUE == true`
    /// * `inout_set | in_set` if `BOTTOM_VALUE == false`
    ///
    /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks.
    /// For clarity, the above statement again from a different perspective:
    /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is
    /// `!BOTTOM_VALUE`.
    ///
    /// There are situations where you want the opposite behaviour: propagate only if *all*
    /// predecessor blocks's value is `!BOTTOM_VALUE`.
    /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This
    /// means that all code paths leading to the location must have set the bit, instead of any
    /// code path leading there.
    ///
    /// If you want this kind of "definitely set" analysis, you need to
    /// 1. Invert `BOTTOM_VALUE`
    /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE`
    /// 3. Override `join` to do the opposite from what it's doing now.
    #[inline]
    fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
        if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) }
    }
}
<commit_msg>Move `MoveDataParamEnv` to beginning of module<commit_after>use rustc::ty;
use rustc_ast::ast::{self, MetaItem};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_span::symbol::{sym, Symbol};

pub(crate) use self::drop_flag_effects::*;
pub use self::impls::borrows::Borrows;
pub use self::impls::DefinitelyInitializedPlaces;
pub use self::impls::EverInitializedPlaces;
pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive};

use self::move_paths::MoveData;

pub mod drop_flag_effects;
pub mod generic;
mod impls;
pub mod move_paths;

pub(crate) mod indexes {
    pub(crate) use super::{
        impls::borrows::BorrowIndex,
        move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
    };
}

pub struct MoveDataParamEnv<'tcx> {
    pub(crate) move_data: MoveData<'tcx>,
    pub(crate) param_env: ty::ParamEnv<'tcx>,
}

pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
    for attr in attrs {
        if attr.check_name(sym::rustc_mir) {
            let items = attr.meta_item_list();
            for item in items.iter().flat_map(|l| l.iter()) {
                match item.meta_item() {
                    Some(mi) if mi.check_name(name) => return Some(mi.clone()),
                    _ => continue,
                }
            }
        }
    }
    None
}

/// Parameterization for the precise form of data flow that is used.
///
/// `BottomValue` determines whether the initial entry set for each basic block is empty or full.
/// This also determines the semantics of the lattice `join` operator used to merge dataflow
/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed
/// point.
///
/// This means, for propagation across the graph, that you either want to start at all-zeroes and
/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect
/// as your merge when propagating.
pub trait BottomValue {
    /// Specifies the initial value for each bit in the entry set for each basic block.
    const BOTTOM_VALUE: bool;

    /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed.
    ///
    /// It is almost certainly wrong to override this, since it automatically applies
    /// * `inout_set & in_set` if `BOTTOM_VALUE == true`
    /// * `inout_set | in_set` if `BOTTOM_VALUE == false`
    ///
    /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks.
    /// For clarity, the above statement again from a different perspective:
    /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is
    /// `!BOTTOM_VALUE`.
    ///
    /// There are situations where you want the opposite behaviour: propagate only if *all*
    /// predecessor blocks's value is `!BOTTOM_VALUE`.
    /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This
    /// means that all code paths leading to the location must have set the bit, instead of any
    /// code path leading there.
    ///
    /// If you want this kind of "definitely set" analysis, you need to
    /// 1. Invert `BOTTOM_VALUE`
    /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE`
    /// 3. Override `join` to do the opposite from what it's doing now.
    #[inline]
    fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
        if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) }
    }
}
<|endoftext|>


<commit_before>use std::os::unix::io::{
    RawFd,
    AsRawFd,
    FromRawFd,
    IntoRawFd,
};
use std::io::{
    Write,
    Read,
    Result,
    Error,
};
use std::process::Stdio;
use std::mem;
use libc;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "netbsd",
          target_os = "openbsd"))]
const FIOCLEX: libc::c_ulong = 0x20006601;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm",
                  target_arch = "aarch64")),
          target_os = "android"))]
const FIOCLEX: libc::c_ulong = 0x5451;

#[cfg(all(target_os = "linux",
          any(target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc")))]
const FIOCLEX: libc::c_ulong = 0x6601;

#[derive(Debug)]
pub struct PipeWriter(FileDesc);

#[derive(Debug)]
pub struct PipeReader(FileDesc);

pub fn pipe() -> Result<(PipeReader, PipeWriter)> {
    let mut fds = [0; 2];
    unsafe {
        if libc::pipe(fds.as_mut_ptr()) == 0 {
            Ok((PipeReader::from_raw_fd(fds[0]), PipeWriter::from_raw_fd(fds[1])))
        } else {
            Err(Error::last_os_error())
        }
    }
}

impl PipeWriter {
    /// Duplicates the underlying file descriptor, returning a new handle to it.
    pub fn dup(&self) -> Result<PipeWriter> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        Ok(PipeWriter(new))
    }

    /// Creates an `Stdio` handle to the underlying pipe, duplicating the file descriptor.
    pub fn stdio(&self) -> Result<Stdio> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        unsafe {
            Ok(Stdio::from_raw_fd(new.into_raw_fd()))
        }
    }
}

impl PipeReader {
    /// Duplicates the underlying file descriptor, returning a new handle to it.
    pub fn dup(&self) -> Result<PipeReader> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        Ok(PipeReader(new))
    }

    /// Creates an `Stdio` handle to the underlying pipe, duplicating the file descriptor.
    pub fn stdio(&self) -> Result<Stdio> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        unsafe {
            Ok(Stdio::from_raw_fd(new.into_raw_fd()))
        }
    }
}

impl AsRawFd for PipeReader {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

impl AsRawFd for PipeWriter {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

impl FromRawFd for PipeReader {
    unsafe fn from_raw_fd(fd: RawFd) -> PipeReader {
        let fd = FileDesc::from_raw_fd(fd);
        fd.set_cloexec();
        PipeReader(fd)
    }
}

impl FromRawFd for PipeWriter {
    unsafe fn from_raw_fd(fd: RawFd) -> PipeWriter {
        let fd = FileDesc::from_raw_fd(fd);
        fd.set_cloexec();
        PipeWriter(fd)
    }
}

impl IntoRawFd for PipeReader {
    fn into_raw_fd(self) -> RawFd {
        self.0.into_raw_fd()
    }
}

impl IntoRawFd for PipeWriter {
    fn into_raw_fd(self) -> RawFd {
        self.0.into_raw_fd()
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }
}

impl Write for PipeWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

#[derive(Debug)]
pub struct FileDesc {
    fd: RawFd,
}

impl AsRawFd for FileDesc {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl FromRawFd for FileDesc {
    unsafe fn from_raw_fd(fd: RawFd) -> FileDesc {
        FileDesc { fd: fd }
    }
}

impl IntoRawFd for FileDesc {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);
        fd
    }
}

impl FileDesc {
    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let ret = unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut libc::c_void,
                       buf.len() as libc::size_t)
        };
        if ret == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        let ret = unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const libc::c_void,
                        buf.len() as libc::size_t)
        };
        if ret == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    pub fn set_cloexec(&self) {
        extern {
            fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
        }

        unsafe {
            let ret = ioctl(self.fd, FIOCLEX);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn dup(&self) -> Result<FileDesc> {
        let res = unsafe {
            libc::dup(self.fd)
        };
        if res == -1 {
            Err(Error::last_os_error())
        } else {
            unsafe {
                Ok(FileDesc::from_raw_fd(res))
            }
        }
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        let _ = unsafe {
            libc::close(self.fd)
        };
    }
}<commit_msg>Add powerpc64 and powerpc64le support<commit_after>use std::os::unix::io::{
    RawFd,
    AsRawFd,
    FromRawFd,
    IntoRawFd,
};
use std::io::{
    Write,
    Read,
    Result,
    Error,
};
use std::process::Stdio;
use std::mem;
use libc;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "netbsd",
          target_os = "openbsd"))]
const FIOCLEX: libc::c_ulong = 0x20006601;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm",
                  target_arch = "aarch64")),
          target_os = "android"))]
const FIOCLEX: libc::c_ulong = 0x5451;

#[cfg(all(target_os = "linux",
          any(target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc")))]
const FIOCLEX: libc::c_ulong = 0x6601;

#[cfg(all(target_os = "linux",
          any(target_arch = "powerpc64",
              target_arch = "powerpc64le")))]
const FIOCLEX: libc::c_ulong = 0x20006601;

#[derive(Debug)]
pub struct PipeWriter(FileDesc);

#[derive(Debug)]
pub struct PipeReader(FileDesc);

pub fn pipe() -> Result<(PipeReader, PipeWriter)> {
    let mut fds = [0; 2];
    unsafe {
        if libc::pipe(fds.as_mut_ptr()) == 0 {
            Ok((PipeReader::from_raw_fd(fds[0]), PipeWriter::from_raw_fd(fds[1])))
        } else {
            Err(Error::last_os_error())
        }
    }
}

impl PipeWriter {
    /// Duplicates the underlying file descriptor, returning a new handle to it.
    pub fn dup(&self) -> Result<PipeWriter> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        Ok(PipeWriter(new))
    }

    /// Creates an `Stdio` handle to the underlying pipe, duplicating the file descriptor.
    pub fn stdio(&self) -> Result<Stdio> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        unsafe {
            Ok(Stdio::from_raw_fd(new.into_raw_fd()))
        }
    }
}

impl PipeReader {
    /// Duplicates the underlying file descriptor, returning a new handle to it.
    pub fn dup(&self) -> Result<PipeReader> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        Ok(PipeReader(new))
    }

    /// Creates an `Stdio` handle to the underlying pipe, duplicating the file descriptor.
    pub fn stdio(&self) -> Result<Stdio> {
        let new = try!(self.0.dup());
        new.set_cloexec();
        unsafe {
            Ok(Stdio::from_raw_fd(new.into_raw_fd()))
        }
    }
}

impl AsRawFd for PipeReader {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

impl AsRawFd for PipeWriter {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

impl FromRawFd for PipeReader {
    unsafe fn from_raw_fd(fd: RawFd) -> PipeReader {
        let fd = FileDesc::from_raw_fd(fd);
        fd.set_cloexec();
        PipeReader(fd)
    }
}

impl FromRawFd for PipeWriter {
    unsafe fn from_raw_fd(fd: RawFd) -> PipeWriter {
        let fd = FileDesc::from_raw_fd(fd);
        fd.set_cloexec();
        PipeWriter(fd)
    }
}

impl IntoRawFd for PipeReader {
    fn into_raw_fd(self) -> RawFd {
        self.0.into_raw_fd()
    }
}

impl IntoRawFd for PipeWriter {
    fn into_raw_fd(self) -> RawFd {
        self.0.into_raw_fd()
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.0.read(buf)
    }
}

impl Write for PipeWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

#[derive(Debug)]
pub struct FileDesc {
    fd: RawFd,
}

impl AsRawFd for FileDesc {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl FromRawFd for FileDesc {
    unsafe fn from_raw_fd(fd: RawFd) -> FileDesc {
        FileDesc { fd: fd }
    }
}

impl IntoRawFd for FileDesc {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);
        fd
    }
}

impl FileDesc {
    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let ret = unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut libc::c_void,
                       buf.len() as libc::size_t)
        };
        if ret == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        let ret = unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const libc::c_void,
                        buf.len() as libc::size_t)
        };
        if ret == -1 {
            Err(Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    pub fn set_cloexec(&self) {
        extern {
            fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
        }

        unsafe {
            let ret = ioctl(self.fd, FIOCLEX);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn dup(&self) -> Result<FileDesc> {
        let res = unsafe {
            libc::dup(self.fd)
        };
        if res == -1 {
            Err(Error::last_os_error())
        } else {
            unsafe {
                Ok(FileDesc::from_raw_fd(res))
            }
        }
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        let _ = unsafe {
            libc::close(self.fd)
        };
    }
}
<|endoftext|>