<commit_before>use descartes::{Band, FiniteCurve, WithUniqueOrthogonal, Norm, Path};
use kay::{Actor, CVec, Individual, Recipient, RecipientAsSwarm, ActorSystem, Swarm, Fate};
use monet::{Instance, Thing, Vertex, UpdateThing};
use core::geometry::{band_to_thing, dash_path};
use super::{Lane, TransferLane, InteractionKind};
use itertools::Itertools;

#[path = "./resources/car.rs"]
mod car;

use super::lane_thing_collector::ThingCollector;

use ::monet::SetupInScene;
use ::monet::AddBatch;

impl RecipientAsSwarm<SetupInScene> for Lane {
    fn receive(_swarm: &mut Swarm<Self>, msg: &SetupInScene) -> Fate {match *msg {
        SetupInScene{renderer_id, scene_id} => {
            renderer_id << AddBatch{scene_id: scene_id, batch_id: 0, thing: car::create()};

            renderer_id << AddBatch{scene_id: scene_id, batch_id: 1333, thing: Thing::new(
                vec![
                    Vertex{position: [-1.0, -1.0, 0.0]},
                    Vertex{position: [1.0, -1.0, 0.0]},
                    Vertex{position: [1.0, 1.0, 0.0]},
                    Vertex{position: [-1.0, 1.0, 0.0]}
                ],
                vec![
                    0, 1, 2,
                    2, 3, 0
                ]
            )};

            Fate::Live
        }
    }}
}

impl RecipientAsSwarm<SetupInScene> for TransferLane {
    fn receive(_swarm: &mut Swarm<Self>, msg: &SetupInScene) -> Fate {match *msg{
        SetupInScene{renderer_id, scene_id} => {
            renderer_id << AddBatch{scene_id: scene_id, batch_id: 1, thing: car::create()};
            Fate::Live
        }
    }}
}

use super::lane_thing_collector::RenderToCollector;
use super::lane_thing_collector::Control::{Update, Freeze};

const CONSTRUCTION_ANIMATION_DELAY : f32 = 120.0;

impl Recipient<RenderToCollector> for Lane {
    fn receive(&mut self, msg: &RenderToCollector) -> Fate {match *msg {
        RenderToCollector(collector_id) => {
            let maybe_path = if self.in_construction - CONSTRUCTION_ANIMATION_DELAY < self.length {
                self.path.subsection(0.0, (self.in_construction - CONSTRUCTION_ANIMATION_DELAY).max(0.0))
            } else {
                Some(self.path.clone())
            };
            if collector_id == ThingCollector::<LaneAsphalt>::id() {
                collector_id << Update(self.id(), maybe_path
                    .map(|path| band_to_thing(&Band::new(path, 3.0), if self.on_intersection {0.2} else {0.0}))
                    .unwrap_or_else(|| Thing::new(vec![], vec![])));
                if self.in_construction - CONSTRUCTION_ANIMATION_DELAY > self.length {
                    collector_id << Freeze(self.id())
                }
            } else {
                let left_marker = maybe_path.clone().and_then(|path|
                    path.shift_orthogonally(2.5)
                ).map(|path| band_to_thing(&Band::new(path, 0.3), 0.1))
                .unwrap_or_else(|| Thing::new(vec![], vec![]));

                let right_marker = maybe_path.and_then(|path|
                    path.shift_orthogonally(-2.5)
                ).map(|path| band_to_thing(&Band::new(path, 0.3), 0.1))
                .unwrap_or_else(|| Thing::new(vec![], vec![]));
                collector_id << Update(self.id(), left_marker + right_marker);
                if self.in_construction - CONSTRUCTION_ANIMATION_DELAY > self.length {
                    collector_id << Freeze(self.id())
                }
            }

            Fate::Live
        }
    }}
}

impl Recipient<RenderToCollector> for TransferLane {
    fn receive(&mut self, msg: &RenderToCollector) -> Fate {match *msg {
        RenderToCollector(collector_id) => {
            let maybe_path = if self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY < self.length {
                self.path.subsection(0.0, (self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY).max(0.0))
            } else {
                Some(self.path.clone())
            };

            collector_id << Update(self.id(), maybe_path
                .map(|path| dash_path(path, 3.0, 6.0).into_iter().map(|dash|
                    band_to_thing(&Band::new(dash, 0.4), 0.2)
                ).sum())
                .unwrap_or_else(|| Thing::new(vec![], vec![])));
            if self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY > self.length {
                collector_id << Freeze(self.id())
            }

            Fate::Live
        }
    }}
}

use ::monet::RenderToScene;
use ::monet::AddInstance;
use ::monet::AddSeveralInstances;

const DEBUG_VIEW_LANDMARKS : bool = false;

impl Recipient<RenderToScene> for Lane {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg {
        RenderToScene{renderer_id, scene_id} => {
            let mut cars_iter = self.cars.iter();
            let mut current_offset = 0.0;
            let mut car_instances = CVec::with_capacity(self.cars.len());
            for segment in self.path.segments().iter() {
                for car in cars_iter.take_while_ref(|car| *car.position - current_offset < segment.length()) {
                    let position2d = segment.along(*car.position - current_offset);
                    let direction = segment.direction_along(*car.position - current_offset);
                    car_instances.push(Instance{
                        instance_position: [position2d.x, position2d.y, 0.0],
                        instance_direction: [direction.x, direction.y],
                        instance_color: if DEBUG_VIEW_LANDMARKS {
                            ::core::geometry::RANDOM_COLORS[
                                car.destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        } else {
                            ::core::geometry::RANDOM_COLORS[
                                car.trip.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        }
                    })
                }
                current_offset += segment.length;
            }

            if self.hovered {
                for &(obstacle, _id) in &self.obstacles {
                    let position2d = if *obstacle.position < self.length {
                        self.path.along(*obstacle.position)
                    } else {
                        self.path.end() + (*obstacle.position - self.length) * self.path.end_direction()
                    };
                    let direction = self.path.direction_along(*obstacle.position);

                    car_instances.push(Instance{
                        instance_position: [position2d.x, position2d.y, 0.0],
                        instance_direction: [direction.x, direction.y],
                        instance_color: [1.0, 0.0, 0.0]
                    });
                }
            }

            renderer_id << AddSeveralInstances{
                scene_id: scene_id,
                batch_id: 0,
                instances: car_instances
            };

            if ! self.interactions.iter().any(|inter| match inter.kind {InteractionKind::Next{..} => true, _ => false}) {
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [self.path.end().x, self.path.end().y, 0.5],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }

            if ! self.interactions.iter().any(|inter| match inter.kind {InteractionKind::Previous{..} => true, _ => false}) {
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [self.path.start().x, self.path.start().y, 0.5],
                    instance_direction: [1.0, 0.0],
                    instance_color: [0.0, 1.0, 0.0]
                }};
            }

            if DEBUG_VIEW_LANDMARKS && self.pathfinding_info.routes_changed {
                let (random_color, is_landmark) = if let Some(as_destination) = self.pathfinding_info.as_destination {
                    let random_color : [f32; 3] = ::core::geometry::RANDOM_COLORS[
                        as_destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                    ];
                    let weaker_random_color = [(random_color[0] + 1.0) / 2.0, (random_color[1] + 1.0) / 2.0, (random_color[2] + 1.0) / 2.0];
                    (weaker_random_color, as_destination.is_landmark())
                } else {
                    ([0.0, 0.0, 0.0], false)
                };

                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 4000 + self.id().instance_id as u16,
                    thing: band_to_thing(&Band::new(self.path.clone(), if is_landmark {2.5} else {1.0}), 0.4),
                    instance: Instance::with_color(random_color)
                };
            }
            Fate::Live
        }
    }}
}

impl Recipient<RenderToScene> for TransferLane {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg{
        RenderToScene{renderer_id, scene_id} => {
            for car in &self.cars {
                let position2d = self.path.along((*car.position).min(self.length));
                let direction = self.path.direction_along((*car.position).min(self.length));
                let rotated_direction = (direction + 0.3 * car.transfer_velocity * direction.orthogonal()).normalize();
                let shifted_position2d = position2d + 2.5 * direction.orthogonal() * car.transfer_position;
                renderer_id << AddInstance{
                    scene_id: scene_id,
                    batch_id: 1,
                    instance: Instance{
                        instance_position: [shifted_position2d.x, shifted_position2d.y, 0.0],
                        instance_direction: [rotated_direction.x, rotated_direction.y],
                        instance_color: if DEBUG_VIEW_LANDMARKS {
                            ::core::geometry::RANDOM_COLORS[
                                car.destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        } else {
                            ::core::geometry::RANDOM_COLORS[
                                car.trip.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        }
                    }
                };
            }
            if self.left.is_none() {
                let position = self.path.along(self.length / 2.0) + self.path.direction_along(self.length / 2.0).orthogonal();
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [position.x, position.y, 0.0],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }
            if self.right.is_none() {
                let position = self.path.along(self.length / 2.0) - self.path.direction_along(self.length / 2.0).orthogonal();
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [position.x, position.y, 0.0],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }
            Fate::Live
        }
    }}
}

use super::lane_thing_collector::Control::Remove;

pub fn on_build(lane: &Lane) {
    lane.id() << RenderToCollector(ThingCollector::<LaneAsphalt>::id());
    if !lane.on_intersection {
        lane.id() << RenderToCollector(ThingCollector::<LaneMarker>::id());
    }
}

pub fn on_build_transfer(lane: &TransferLane) {
    lane.id() << RenderToCollector(ThingCollector::<TransferLaneMarkerGaps>::id());
}

pub fn on_unbuild(lane: &Lane) {
    ThingCollector::<LaneAsphalt>::id() << Remove(lane.id());
    if !lane.on_intersection {
        ThingCollector::<LaneMarker>::id() << Remove(lane.id());
    }

    if DEBUG_VIEW_LANDMARKS {
        // TODO: ugly
        ::monet::Renderer::id() << UpdateThing{
            scene_id: 0,
            thing_id: 4000 + lane.id().instance_id as u16,
            thing: Thing::new(vec![], vec![]),
            instance: Instance::with_color([0.0, 0.0, 0.0])
        };
    }
}

pub fn on_unbuild_transfer(lane: &TransferLane) {
    ThingCollector::<TransferLaneMarkerGaps>::id() << Remove(lane.id());
}

#[derive(Clone)]
pub struct LaneAsphalt;
#[derive(Clone)]
pub struct LaneMarker;
#[derive(Clone)]
pub struct TransferLaneMarkerGaps;

pub fn setup(system: &mut ActorSystem) {
    system.add_inbox::<SetupInScene, Swarm<Lane>>();
    system.add_inbox::<RenderToCollector, Swarm<Lane>>();
    system.add_inbox::<RenderToScene, Swarm<Lane>>();
    super::lane_thing_collector::setup::<LaneAsphalt>(system, [0.7, 0.7, 0.7], 2000);
    super::lane_thing_collector::setup::<LaneMarker>(system, [1.0, 1.0, 1.0], 2100);

    system.add_inbox::<SetupInScene, Swarm<TransferLane>>();
    system.add_inbox::<RenderToCollector, Swarm<TransferLane>>();
    system.add_inbox::<RenderToScene, Swarm<TransferLane>>();
    super::lane_thing_collector::setup::<TransferLaneMarkerGaps>(system, [0.7, 0.7, 0.7], 2200);

    super::planning::setup(system);
}<commit_msg>Slight optimization of transfer lane car rendering<commit_after>use descartes::{Band, FiniteCurve, WithUniqueOrthogonal, Norm, Path};
use kay::{Actor, CVec, Individual, Recipient, RecipientAsSwarm, ActorSystem, Swarm, Fate};
use monet::{Instance, Thing, Vertex, UpdateThing};
use core::geometry::{band_to_thing, dash_path};
use super::{Lane, TransferLane, InteractionKind};
use itertools::Itertools;

#[path = "./resources/car.rs"]
mod car;

use super::lane_thing_collector::ThingCollector;

use ::monet::SetupInScene;
use ::monet::AddBatch;

impl RecipientAsSwarm<SetupInScene> for Lane {
    fn receive(_swarm: &mut Swarm<Self>, msg: &SetupInScene) -> Fate {match *msg {
        SetupInScene{renderer_id, scene_id} => {
            renderer_id << AddBatch{scene_id: scene_id, batch_id: 0, thing: car::create()};

            renderer_id << AddBatch{scene_id: scene_id, batch_id: 1333, thing: Thing::new(
                vec![
                    Vertex{position: [-1.0, -1.0, 0.0]},
                    Vertex{position: [1.0, -1.0, 0.0]},
                    Vertex{position: [1.0, 1.0, 0.0]},
                    Vertex{position: [-1.0, 1.0, 0.0]}
                ],
                vec![
                    0, 1, 2,
                    2, 3, 0
                ]
            )};

            Fate::Live
        }
    }}
}

impl RecipientAsSwarm<SetupInScene> for TransferLane {
    fn receive(_swarm: &mut Swarm<Self>, msg: &SetupInScene) -> Fate {match *msg{
        SetupInScene{renderer_id, scene_id} => {
            renderer_id << AddBatch{scene_id: scene_id, batch_id: 1, thing: car::create()};
            Fate::Live
        }
    }}
}

use super::lane_thing_collector::RenderToCollector;
use super::lane_thing_collector::Control::{Update, Freeze};

const CONSTRUCTION_ANIMATION_DELAY : f32 = 120.0;

impl Recipient<RenderToCollector> for Lane {
    fn receive(&mut self, msg: &RenderToCollector) -> Fate {match *msg {
        RenderToCollector(collector_id) => {
            let maybe_path = if self.in_construction - CONSTRUCTION_ANIMATION_DELAY < self.length {
                self.path.subsection(0.0, (self.in_construction - CONSTRUCTION_ANIMATION_DELAY).max(0.0))
            } else {
                Some(self.path.clone())
            };
            if collector_id == ThingCollector::<LaneAsphalt>::id() {
                collector_id << Update(self.id(), maybe_path
                    .map(|path| band_to_thing(&Band::new(path, 3.0), if self.on_intersection {0.2} else {0.0}))
                    .unwrap_or_else(|| Thing::new(vec![], vec![])));
                if self.in_construction - CONSTRUCTION_ANIMATION_DELAY > self.length {
                    collector_id << Freeze(self.id())
                }
            } else {
                let left_marker = maybe_path.clone().and_then(|path|
                    path.shift_orthogonally(2.5)
                ).map(|path| band_to_thing(&Band::new(path, 0.3), 0.1))
                .unwrap_or_else(|| Thing::new(vec![], vec![]));

                let right_marker = maybe_path.and_then(|path|
                    path.shift_orthogonally(-2.5)
                ).map(|path| band_to_thing(&Band::new(path, 0.3), 0.1))
                .unwrap_or_else(|| Thing::new(vec![], vec![]));
                collector_id << Update(self.id(), left_marker + right_marker);
                if self.in_construction - CONSTRUCTION_ANIMATION_DELAY > self.length {
                    collector_id << Freeze(self.id())
                }
            }

            Fate::Live
        }
    }}
}

impl Recipient<RenderToCollector> for TransferLane {
    fn receive(&mut self, msg: &RenderToCollector) -> Fate {match *msg {
        RenderToCollector(collector_id) => {
            let maybe_path = if self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY < self.length {
                self.path.subsection(0.0, (self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY).max(0.0))
            } else {
                Some(self.path.clone())
            };

            collector_id << Update(self.id(), maybe_path
                .map(|path| dash_path(path, 3.0, 6.0).into_iter().map(|dash|
                    band_to_thing(&Band::new(dash, 0.4), 0.2)
                ).sum())
                .unwrap_or_else(|| Thing::new(vec![], vec![])));
            if self.in_construction - 2.0 * CONSTRUCTION_ANIMATION_DELAY > self.length {
                collector_id << Freeze(self.id())
            }

            Fate::Live
        }
    }}
}

use ::monet::RenderToScene;
use ::monet::AddInstance;
use ::monet::AddSeveralInstances;

const DEBUG_VIEW_LANDMARKS : bool = false;

impl Recipient<RenderToScene> for Lane {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg {
        RenderToScene{renderer_id, scene_id} => {
            let mut cars_iter = self.cars.iter();
            let mut current_offset = 0.0;
            let mut car_instances = CVec::with_capacity(self.cars.len());
            for segment in self.path.segments().iter() {
                for car in cars_iter.take_while_ref(|car| *car.position - current_offset < segment.length()) {
                    let position2d = segment.along(*car.position - current_offset);
                    let direction = segment.direction_along(*car.position - current_offset);
                    car_instances.push(Instance{
                        instance_position: [position2d.x, position2d.y, 0.0],
                        instance_direction: [direction.x, direction.y],
                        instance_color: if DEBUG_VIEW_LANDMARKS {
                            ::core::geometry::RANDOM_COLORS[
                                car.destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        } else {
                            ::core::geometry::RANDOM_COLORS[
                                car.trip.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        }
                    })
                }
                current_offset += segment.length;
            }

            if self.hovered {
                for &(obstacle, _id) in &self.obstacles {
                    let position2d = if *obstacle.position < self.length {
                        self.path.along(*obstacle.position)
                    } else {
                        self.path.end() + (*obstacle.position - self.length) * self.path.end_direction()
                    };
                    let direction = self.path.direction_along(*obstacle.position);

                    car_instances.push(Instance{
                        instance_position: [position2d.x, position2d.y, 0.0],
                        instance_direction: [direction.x, direction.y],
                        instance_color: [1.0, 0.0, 0.0]
                    });
                }
            }

            if !car_instances.is_empty() {
                renderer_id << AddSeveralInstances{
                    scene_id: scene_id,
                    batch_id: 0,
                    instances: car_instances
                };
            }

            if ! self.interactions.iter().any(|inter| match inter.kind {InteractionKind::Next{..} => true, _ => false}) {
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [self.path.end().x, self.path.end().y, 0.5],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }

            if ! self.interactions.iter().any(|inter| match inter.kind {InteractionKind::Previous{..} => true, _ => false}) {
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [self.path.start().x, self.path.start().y, 0.5],
                    instance_direction: [1.0, 0.0],
                    instance_color: [0.0, 1.0, 0.0]
                }};
            }

            if DEBUG_VIEW_LANDMARKS && self.pathfinding_info.routes_changed {
                let (random_color, is_landmark) = if let Some(as_destination) = self.pathfinding_info.as_destination {
                    let random_color : [f32; 3] = ::core::geometry::RANDOM_COLORS[
                        as_destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                    ];
                    let weaker_random_color = [(random_color[0] + 1.0) / 2.0, (random_color[1] + 1.0) / 2.0, (random_color[2] + 1.0) / 2.0];
                    (weaker_random_color, as_destination.is_landmark())
                } else {
                    ([0.0, 0.0, 0.0], false)
                };

                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 4000 + self.id().instance_id as u16,
                    thing: band_to_thing(&Band::new(self.path.clone(), if is_landmark {2.5} else {1.0}), 0.4),
                    instance: Instance::with_color(random_color)
                };
            }
            Fate::Live
        }
    }}
}

impl Recipient<RenderToScene> for TransferLane {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg{
        RenderToScene{renderer_id, scene_id} => {
            let mut cars_iter = self.cars.iter();
            let mut current_offset = 0.0;
            let mut car_instances = CVec::with_capacity(self.cars.len());
            for segment in self.path.segments().iter() {
                for car in cars_iter.take_while_ref(|car| *car.position - current_offset < segment.length()) {
                    let position2d = segment.along(*car.position - current_offset);
                    let direction = segment.direction_along(*car.position - current_offset);
                    let rotated_direction = (direction + 0.3 * car.transfer_velocity * direction.orthogonal()).normalize();
                    let shifted_position2d = position2d + 2.5 * direction.orthogonal() * car.transfer_position;
                    car_instances.push(Instance{
                        instance_position: [shifted_position2d.x, shifted_position2d.y, 0.0],
                        instance_direction: [rotated_direction.x, rotated_direction.y],
                        instance_color: if DEBUG_VIEW_LANDMARKS {
                            ::core::geometry::RANDOM_COLORS[
                                car.destination.landmark.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        } else {
                            ::core::geometry::RANDOM_COLORS[
                                car.trip.instance_id as usize % ::core::geometry::RANDOM_COLORS.len()
                            ]
                        }
                    })
                }
                current_offset += segment.length;
            }

            if !car_instances.is_empty() {
                renderer_id << AddSeveralInstances{
                    scene_id: scene_id,
                    batch_id: 0,
                    instances: car_instances
                };
            }

            if self.left.is_none() {
                let position = self.path.along(self.length / 2.0) + self.path.direction_along(self.length / 2.0).orthogonal();
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [position.x, position.y, 0.0],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }
            if self.right.is_none() {
                let position = self.path.along(self.length / 2.0) - self.path.direction_along(self.length / 2.0).orthogonal();
                renderer_id << AddInstance{scene_id: scene_id, batch_id: 1333, instance: Instance{
                    instance_position: [position.x, position.y, 0.0],
                    instance_direction: [1.0, 0.0],
                    instance_color: [1.0, 0.0, 0.0]
                }};
            }
            Fate::Live
        }
    }}
}

use super::lane_thing_collector::Control::Remove;

pub fn on_build(lane: &Lane) {
    lane.id() << RenderToCollector(ThingCollector::<LaneAsphalt>::id());
    if !lane.on_intersection {
        lane.id() << RenderToCollector(ThingCollector::<LaneMarker>::id());
    }
}

pub fn on_build_transfer(lane: &TransferLane) {
    lane.id() << RenderToCollector(ThingCollector::<TransferLaneMarkerGaps>::id());
}

pub fn on_unbuild(lane: &Lane) {
    ThingCollector::<LaneAsphalt>::id() << Remove(lane.id());
    if !lane.on_intersection {
        ThingCollector::<LaneMarker>::id() << Remove(lane.id());
    }

    if DEBUG_VIEW_LANDMARKS {
        // TODO: ugly
        ::monet::Renderer::id() << UpdateThing{
            scene_id: 0,
            thing_id: 4000 + lane.id().instance_id as u16,
            thing: Thing::new(vec![], vec![]),
            instance: Instance::with_color([0.0, 0.0, 0.0])
        };
    }
}

pub fn on_unbuild_transfer(lane: &TransferLane) {
    ThingCollector::<TransferLaneMarkerGaps>::id() << Remove(lane.id());
}

#[derive(Clone)]
pub struct LaneAsphalt;
#[derive(Clone)]
pub struct LaneMarker;
#[derive(Clone)]
pub struct TransferLaneMarkerGaps;

pub fn setup(system: &mut ActorSystem) {
    system.add_inbox::<SetupInScene, Swarm<Lane>>();
    system.add_inbox::<RenderToCollector, Swarm<Lane>>();
    system.add_inbox::<RenderToScene, Swarm<Lane>>();
    super::lane_thing_collector::setup::<LaneAsphalt>(system, [0.7, 0.7, 0.7], 2000);
    super::lane_thing_collector::setup::<LaneMarker>(system, [1.0, 1.0, 1.0], 2100);

    system.add_inbox::<SetupInScene, Swarm<TransferLane>>();
    system.add_inbox::<RenderToCollector, Swarm<TransferLane>>();
    system.add_inbox::<RenderToScene, Swarm<TransferLane>>();
    super::lane_thing_collector::setup::<TransferLaneMarkerGaps>(system, [0.7, 0.7, 0.7], 2200);

    super::planning::setup(system);
}<|endoftext|>


<commit_before>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::prelude::*;
use dirs;
use serde_yaml;
use std::{fs::{self,
               File},
          io::Write,
          path::PathBuf};

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from("1.0"), }
    }
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if license_exists() {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(license_path())?;
    let mut file = File::create(license_file())?;
    file.write_all(content.as_bytes())?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn license_path() -> PathBuf {
    let hab_dir = if am_i_root() {
        PathBuf::from(&*FS_ROOT_PATH).join("hab")
    } else if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    };

    hab_dir.join("accepted-licenses")
}

fn license_file() -> PathBuf { license_path().join("habitat") }

fn license_exists() -> bool { license_file().is_file() }
<commit_msg>Address PR feedback<commit_after>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::prelude::*;
use dirs;
use serde_yaml;
use std::{fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if license_exists() {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(license_path())?;
    let mut file = File::create(license_file())?;
    file.write_all(content.as_bytes())?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn license_path() -> PathBuf {
    let hab_dir = if am_i_root() {
        PathBuf::from(&*FS_ROOT_PATH).join("hab")
    } else if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    };

    hab_dir.join("accepted-licenses")
}

fn license_file() -> PathBuf { license_path().join("habitat") }

fn license_exists() -> bool { license_file().is_file() }
<|endoftext|>


<commit_before>//! This module defines the `DepNode` type which the compiler uses to represent
//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
//! uniquely identify a given commit and has a few advantages:
//!
//! * A `DepNode` can simply be serialized to disk and loaded in another session
//!   without the need to do any "rebasing (like we have to do for Spans and
//!   NodeIds) or "retracing" like we had to do for `DefId` in earlier
//!   implementations of the dependency graph.
//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
//!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
//!   memory without any post-processing (e.g., "abomination-style" pointer
//!   reconstruction).
//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
//!   refer to things that do not exist anymore. In previous implementations
//!   `DepNode` contained a `DefId`. A `DepNode` referring to something that
//!   had been removed between the previous and the current compilation session
//!   could not be instantiated because the current compilation session
//!   contained no `DefId` for thing that had been removed.
//!
//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
//! runtime in order to construct a valid `DepNode` fingerprint.
//!
//! Because the macro sees what parameters a given `DepKind` requires, it can
//! "infer" some properties for each kind of `DepNode`:
//!
//! * Whether a `DepNode` of a given kind has any parameters at all. Some
//!   `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//!   given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//!   in which case it is possible to map the node's fingerprint back to the
//!   `DefId` it was computed from. In other cases, too much information gets
//!   lost during fingerprint computation.
//!
//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only
//! valid `DepNode` instances can be constructed. For example, the API does not
//! allow for constructing parameterless `DepNode`s with anything other
//! than a zeroed out fingerprint. More generally speaking, it relieves the
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_span::symbol::Symbol;
use std::hash::Hash;

pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};

// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e., which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
macro_rules! erase {
    ($x:tt) => {{}};
}

macro_rules! is_anon_attr {
    (anon) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! is_eval_always_attr {
    (eval_always) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! contains_anon_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
}

macro_rules! contains_eval_always_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}

macro_rules! define_dep_nodes {
    (<$tcx:tt>
    $(
        [$($attrs:tt)*]
        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
      ,)*
    ) => (
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
                 RustcEncodable, RustcDecodable)]
        #[allow(non_camel_case_types)]
        pub enum DepKind {
            $($variant),*
        }

        impl DepKind {
            #[allow(unreachable_code)]
            pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            if contains_anon_attr!($($attrs)*) {
                                return false;
                            }

                            // tuple args
                            $({
                                return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
                                    ::can_reconstruct_query_key();
                            })*

                            true
                        }
                    )*
                }
            }

            pub fn is_anon(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
                    )*
                }
            }

            pub fn is_eval_always(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
                    )*
                }
            }

            #[allow(unreachable_code)]
            pub fn has_params(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            // tuple args
                            $({
                                erase!($tuple_arg_ty);
                                return true;
                            })*

                            false
                        }
                    )*
                }
            }
        }

        pub struct DepConstructor;

        #[allow(non_camel_case_types)]
        impl DepConstructor {
            $(
                #[inline(always)]
                #[allow(unreachable_code, non_snake_case)]
                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
                    // tuple args
                    $({
                        erase!($tuple_arg_ty);
                        return DepNode::construct(_tcx, DepKind::$variant, &arg)
                    })*

                    return DepNode::construct(_tcx, DepKind::$variant, &())
                }
            )*
        }

        pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;

        pub trait DepNodeExt: Sized {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash)
                -> Result<Self, ()>;

            /// Used in testing
            fn has_label_string(label: &str) -> bool;
        }

        impl DepNodeExt for DepNode {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                DepNode {
                    kind,
                    hash: def_path_hash.0,
                }
            }

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
                if self.kind.can_reconstruct_query_key() {
                    let def_path_hash = DefPathHash(self.hash);
                    tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
                } else {
                    None
                }
            }

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
                let kind = match label {
                    $(
                        stringify!($variant) => DepKind::$variant,
                    )*
                    _ => return Err(()),
                };

                if !kind.can_reconstruct_query_key() {
                    return Err(());
                }

                if kind.has_params() {
                    Ok(DepNode::from_def_path_hash(def_path_hash, kind))
                } else {
                    Ok(DepNode::new_no_params(kind))
                }
            }

            /// Used in testing
            fn has_label_string(label: &str) -> bool {
                match label {
                    $(
                        stringify!($variant) => true,
                    )*
                    _ => false,
                }
            }
        }

        /// Contains variant => str representations for constructing
        /// DepNode groups for tests.
        #[allow(dead_code, non_upper_case_globals)]
        pub mod label_strs {
           $(
                pub const $variant: &str = stringify!($variant);
            )*
        }
    );
}

rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
    // We use this for most things when incr. comp. is turned off.
    [] Null,

    // Represents metadata from an extern crate.
    [eval_always] CrateMetadata(CrateNum),

    [anon] TraitSelect,

    [] CompileCodegenUnit(Symbol),
]);

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        tcx.def_path_hash(*self).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.def_path_str(*self)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        self.to_def_id().to_fingerprint(tcx)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        self.to_def_id().to_debug_str(tcx)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
        tcx.def_path_hash(def_id).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.crate_name(*self).to_string()
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.krate)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let (def_id_0, def_id_1) = *self;

        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
        let def_path_hash_1 = tcx.def_path_hash(def_id_1);

        def_path_hash_0.0.combine(def_path_hash_1.0)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        let (def_id_0, def_id_1) = *self;

        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let HirId { owner, local_id } = *self;

        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
        let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());

        def_path_hash.0.combine(local_id)
    }
}
<commit_msg>Rollup merge of #74353 - pierwill:pierwill-edit-dep-node, r=jonas-schievink<commit_after>//! This module defines the `DepNode` type which the compiler uses to represent
//! nodes in the dependency graph.
//!
//! A `DepNode` consists of a `DepKind` (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
//! uniquely identify a given commit and has a few advantages:
//!
//! * A `DepNode` can simply be serialized to disk and loaded in another session
//!   without the need to do any "rebasing" (like we have to do for Spans and
//!   NodeIds) or "retracing" (like we had to do for `DefId` in earlier
//!   implementations of the dependency graph).
//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
//!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
//!   memory without any post-processing (e.g., "abomination-style" pointer
//!   reconstruction).
//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
//!   refer to things that do not exist anymore. In previous implementations
//!   `DepNode` contained a `DefId`. A `DepNode` referring to something that
//!   had been removed between the previous and the current compilation session
//!   could not be instantiated because the current compilation session
//!   contained no `DefId` for thing that had been removed.
//!
//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
//! runtime in order to construct a valid `DepNode` fingerprint.
//!
//! Because the macro sees what parameters a given `DepKind` requires, it can
//! "infer" some properties for each kind of `DepNode`:
//!
//! * Whether a `DepNode` of a given kind has any parameters at all. Some
//!   `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//!   given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//!   in which case it is possible to map the node's fingerprint back to the
//!   `DefId` it was computed from. In other cases, too much information gets
//!   lost during fingerprint computation.
//!
//! The `DepConstructor` enum, together with `DepNode::new()`, ensures that only
//! valid `DepNode` instances can be constructed. For example, the API does not
//! allow for constructing parameterless `DepNode`s with anything other
//! than a zeroed out fingerprint. More generally speaking, it relieves the
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_span::symbol::Symbol;
use std::hash::Hash;

pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};

// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e., which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
macro_rules! erase {
    ($x:tt) => {{}};
}

macro_rules! is_anon_attr {
    (anon) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! is_eval_always_attr {
    (eval_always) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! contains_anon_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
}

macro_rules! contains_eval_always_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}

macro_rules! define_dep_nodes {
    (<$tcx:tt>
    $(
        [$($attrs:tt)*]
        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
      ,)*
    ) => (
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
                 RustcEncodable, RustcDecodable)]
        #[allow(non_camel_case_types)]
        pub enum DepKind {
            $($variant),*
        }

        impl DepKind {
            #[allow(unreachable_code)]
            pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            if contains_anon_attr!($($attrs)*) {
                                return false;
                            }

                            // tuple args
                            $({
                                return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
                                    ::can_reconstruct_query_key();
                            })*

                            true
                        }
                    )*
                }
            }

            pub fn is_anon(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
                    )*
                }
            }

            pub fn is_eval_always(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
                    )*
                }
            }

            #[allow(unreachable_code)]
            pub fn has_params(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            // tuple args
                            $({
                                erase!($tuple_arg_ty);
                                return true;
                            })*

                            false
                        }
                    )*
                }
            }
        }

        pub struct DepConstructor;

        #[allow(non_camel_case_types)]
        impl DepConstructor {
            $(
                #[inline(always)]
                #[allow(unreachable_code, non_snake_case)]
                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
                    // tuple args
                    $({
                        erase!($tuple_arg_ty);
                        return DepNode::construct(_tcx, DepKind::$variant, &arg)
                    })*

                    return DepNode::construct(_tcx, DepKind::$variant, &())
                }
            )*
        }

        pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;

        pub trait DepNodeExt: Sized {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash)
                -> Result<Self, ()>;

            /// Used in testing
            fn has_label_string(label: &str) -> bool;
        }

        impl DepNodeExt for DepNode {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                DepNode {
                    kind,
                    hash: def_path_hash.0,
                }
            }

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
                if self.kind.can_reconstruct_query_key() {
                    let def_path_hash = DefPathHash(self.hash);
                    tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
                } else {
                    None
                }
            }

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
                let kind = match label {
                    $(
                        stringify!($variant) => DepKind::$variant,
                    )*
                    _ => return Err(()),
                };

                if !kind.can_reconstruct_query_key() {
                    return Err(());
                }

                if kind.has_params() {
                    Ok(DepNode::from_def_path_hash(def_path_hash, kind))
                } else {
                    Ok(DepNode::new_no_params(kind))
                }
            }

            /// Used in testing
            fn has_label_string(label: &str) -> bool {
                match label {
                    $(
                        stringify!($variant) => true,
                    )*
                    _ => false,
                }
            }
        }

        /// Contains variant => str representations for constructing
        /// DepNode groups for tests.
        #[allow(dead_code, non_upper_case_globals)]
        pub mod label_strs {
           $(
                pub const $variant: &str = stringify!($variant);
            )*
        }
    );
}

rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
    // We use this for most things when incr. comp. is turned off.
    [] Null,

    // Represents metadata from an extern crate.
    [eval_always] CrateMetadata(CrateNum),

    [anon] TraitSelect,

    [] CompileCodegenUnit(Symbol),
]);

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        tcx.def_path_hash(*self).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.def_path_str(*self)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        self.to_def_id().to_fingerprint(tcx)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        self.to_def_id().to_debug_str(tcx)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
        tcx.def_path_hash(def_id).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.crate_name(*self).to_string()
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.krate)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let (def_id_0, def_id_1) = *self;

        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
        let def_path_hash_1 = tcx.def_path_hash(def_id_1);

        def_path_hash_0.0.combine(def_path_hash_1.0)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        let (def_id_0, def_id_1) = *self;

        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let HirId { owner, local_id } = *self;

        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
        let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());

        def_path_hash.0.combine(local_id)
    }
}
<|endoftext|>


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

#![feature(globs, macro_rules, phase, thread_local, link_args)]

#![allow(experimental, non_camel_case_types)]
#![deny(unused_imports, unused_variables, unused_mut)]

#![feature(phase)]
#[phase(plugin, link)]
extern crate log;
#[phase(plugin)]
extern crate "plugins" as servo_plugins;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate geom;
extern crate gfx;
extern crate gleam;
extern crate glfw;
extern crate glfw_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate script;

extern crate "net" as servo_net;
extern crate "msg" as servo_msg;
extern crate "util" as servo_util;
extern crate style;
extern crate stb_image;

extern crate green;
extern crate native;
extern crate rustrt;
extern crate libc;
extern crate "url" as std_url;

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<commit_msg>Remove unused libgreen import.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(globs, macro_rules, phase, thread_local, link_args)]

#![allow(experimental, non_camel_case_types)]
#![deny(unused_imports, unused_variables, unused_mut)]

#![feature(phase)]
#[phase(plugin, link)]
extern crate log;
#[phase(plugin)]
extern crate "plugins" as servo_plugins;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate geom;
extern crate gfx;
extern crate gleam;
extern crate glfw;
extern crate glfw_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate script;

extern crate "net" as servo_net;
extern crate "msg" as servo_msg;
extern crate "util" as servo_util;
extern crate style;
extern crate stb_image;

extern crate native;
extern crate rustrt;
extern crate libc;
extern crate "url" as std_url;

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<|endoftext|>


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

#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]
#![allow(doc_markdown)]

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate clap;
#[cfg(feature = "dbus_enabled")]
extern crate dbus;
extern crate env_logger;
extern crate libc;
extern crate libudev;
extern crate nix;

use std::cell::RefCell;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{ErrorKind, Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg, ArgMatches};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature = "dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: &StratisError) -> () {
    eprintln!("{}", err);
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s);
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(Device, PathBuf)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device.devnode().and_then(|devnode| {
            device
                .devnum()
                .and_then(|devnum| Some((Device::from(devnum), PathBuf::from(devnode))))
        });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = match OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
    {
        Ok(f) => f,
        Err(e) => {
            if e.kind() == ErrorKind::PermissionDenied {
                return Err(StratisError::Error(
                    "Must be running as root in order to start daemon.".to_string(),
                ));
            }
            return Err(e.into());
        }
    };
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!(
                "Daemon already running with pid: {}",
                pid_str
            )))
        }
    }
}

fn run(matches: &ArgMatches) -> StratisResult<()> {
    // Setup a udev listener before initializing the engine. A device may
    // appear after the engine has read the /dev directory but before it has
    // completed initialization. Unless the udev event has been recorded, the
    // engine will miss the device.
    // This is especially important since stratisd must run during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    /*
    fds is a Vec of libc::pollfd structs. Ideally, it would be possible
    to use the higher level nix crate to handle polling. If this were possible,
    then the Vec would be one of nix::poll::PollFds and this would be more
    rustic. Unfortunately, the rust D-Bus library requires an explicit file
    descriptor to be passed as an argument to Connection::watch_handle(),
    and the explicit file descriptor can not be extracted from the PollFd
    struct. So, at this time, sticking with libc is less complex than
    converting to using nix, because if using nix, the file descriptor would
    have to be maintained in the Vec as well as the PollFd struct.
    */
    let mut fds = Vec::new();

    fds.push(libc::pollfd {
        fd: udev.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    let eventable = engine.borrow().get_eventable();

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                fd: evt.get_pollable_fd(),
                revents: 0,
                events: libc::POLLIN,
            });

            (-1, FD_INDEX_ENGINE + 1)
        }
        None => (10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature = "dbus_enabled")]
    let (dbus_conn, mut tree, base_object_path, dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    #[cfg(feature = "dbus_enabled")]
    for (_, pool_uuid, pool) in engine.borrow().pools() {
        libstratis::dbus_api::register_pool(
            &dbus_conn,
            &dbus_context,
            &mut tree,
            pool_uuid,
            pool,
            &base_object_path,
        )?;
    }

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            while let Some(event) = udev.receive_event() {
                if let Some((device, devnode)) = handle_udev_add(&event) {
                    // If block evaluate returns an error we are going to ignore it as
                    // there is nothing we can do for a device we are getting errors with.
                    let pool_uuid = engine
                        .borrow_mut()
                        .block_evaluate(device, devnode)
                        .unwrap_or(None);

                    // We need to pretend that we aren't using the variable _pool_uuid so
                    // that we can conditionally compile out the register_pool when dbus
                    // is not enabled.
                    if let Some(_pool_uuid) = pool_uuid {
                        #[cfg(feature = "dbus_enabled")]
                        libstratis::dbus_api::register_pool(
                            &dbus_conn,
                            &dbus_context,
                            &mut tree,
                            _pool_uuid,
                            engine
                                .borrow()
                                .get_pool(_pool_uuid)
                                .expect(
                                    "block_evaluate() returned a pool UUID, pool must be available",
                                )
                                .1,
                            &base_object_path,
                        )?;
                    }
                }
            }
        }

        // Handle engine events, if the engine is eventable
        match eventable {
            Some(ref evt) => {
                if fds[FD_INDEX_ENGINE].revents != 0 {
                    fds[FD_INDEX_ENGINE].revents = 0;
                    evt.clear_event()?;
                    engine.borrow_mut().evented()?;
                }
            }
            None => {
                // Unconditionally call evented() if engine has no eventable.
                // This looks like a bad idea, but the only engine that has
                // no eventable is the sim engine, and for that engine,
                // evented() is essentially a no-op.
                engine.borrow_mut().evented()?;
            }
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature = "dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                .iter()
                .filter(|pfd| pfd.revents != 0)
            {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) =
                        libstratis::dbus_api::handle(&dbus_conn, &item, &mut tree, &dbus_context)
                    {
                        print_err(&From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(
            Arg::with_name("debug")
                .long("debug")
                .help("Print additional output for debugging"),
        )
        .arg(
            Arg::with_name("sim")
                .long("sim")
                .help("Use simulator engine"),
        )
        .get_matches();

    let result = trylock_pid_file()
        .and_then(|_pidfile| {
            Ok(initialize_log(matches.is_present("debug"))
                .expect("This is the first and only invocation of this method; it must succeed."))
        })
        .and_then(|_| run(&matches));
    if let Err(err) = result {
        print_err(&err);
        exit(1);
    } else {
        exit(0);
    }
}
<commit_msg>Change assertion to an error return<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]
#![allow(doc_markdown)]

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate clap;
#[cfg(feature = "dbus_enabled")]
extern crate dbus;
extern crate env_logger;
extern crate libc;
extern crate libudev;
extern crate nix;

use std::cell::RefCell;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{ErrorKind, Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg, ArgMatches};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature = "dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: &StratisError) -> () {
    eprintln!("{}", err);
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s);
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(Device, PathBuf)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device.devnode().and_then(|devnode| {
            device
                .devnum()
                .and_then(|devnum| Some((Device::from(devnum), PathBuf::from(devnode))))
        });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = match OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
    {
        Ok(f) => f,
        Err(e) => {
            if e.kind() == ErrorKind::PermissionDenied {
                return Err(StratisError::Error(
                    "Must be running as root in order to start daemon.".to_string(),
                ));
            }
            return Err(e.into());
        }
    };
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!(
                "Daemon already running with pid: {}",
                pid_str
            )))
        }
    }
}

fn run(matches: &ArgMatches) -> StratisResult<()> {
    // Setup a udev listener before initializing the engine. A device may
    // appear after the engine has read the /dev directory but before it has
    // completed initialization. Unless the udev event has been recorded, the
    // engine will miss the device.
    // This is especially important since stratisd must run during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    /*
    fds is a Vec of libc::pollfd structs. Ideally, it would be possible
    to use the higher level nix crate to handle polling. If this were possible,
    then the Vec would be one of nix::poll::PollFds and this would be more
    rustic. Unfortunately, the rust D-Bus library requires an explicit file
    descriptor to be passed as an argument to Connection::watch_handle(),
    and the explicit file descriptor can not be extracted from the PollFd
    struct. So, at this time, sticking with libc is less complex than
    converting to using nix, because if using nix, the file descriptor would
    have to be maintained in the Vec as well as the PollFd struct.
    */
    let mut fds = Vec::new();

    fds.push(libc::pollfd {
        fd: udev.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    let eventable = engine.borrow().get_eventable();

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                fd: evt.get_pollable_fd(),
                revents: 0,
                events: libc::POLLIN,
            });

            (-1, FD_INDEX_ENGINE + 1)
        }
        None => (10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature = "dbus_enabled")]
    let (dbus_conn, mut tree, base_object_path, dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    #[cfg(feature = "dbus_enabled")]
    for (_, pool_uuid, pool) in engine.borrow().pools() {
        libstratis::dbus_api::register_pool(
            &dbus_conn,
            &dbus_context,
            &mut tree,
            pool_uuid,
            pool,
            &base_object_path,
        )?;
    }

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            while let Some(event) = udev.receive_event() {
                if let Some((device, devnode)) = handle_udev_add(&event) {
                    // If block evaluate returns an error we are going to ignore it as
                    // there is nothing we can do for a device we are getting errors with.
                    let pool_uuid = engine
                        .borrow_mut()
                        .block_evaluate(device, devnode)
                        .unwrap_or(None);

                    // We need to pretend that we aren't using the variable _pool_uuid so
                    // that we can conditionally compile out the register_pool when dbus
                    // is not enabled.
                    if let Some(_pool_uuid) = pool_uuid {
                        #[cfg(feature = "dbus_enabled")]
                        libstratis::dbus_api::register_pool(
                            &dbus_conn,
                            &dbus_context,
                            &mut tree,
                            _pool_uuid,
                            engine
                                .borrow()
                                .get_pool(_pool_uuid)
                                .expect(
                                    "block_evaluate() returned a pool UUID, pool must be available",
                                )
                                .1,
                            &base_object_path,
                        )?;
                    }
                }
            }
        }

        // Handle engine events, if the engine is eventable
        match eventable {
            Some(ref evt) => {
                if fds[FD_INDEX_ENGINE].revents != 0 {
                    fds[FD_INDEX_ENGINE].revents = 0;
                    evt.clear_event()?;
                    engine.borrow_mut().evented()?;
                }
            }
            None => {
                // Unconditionally call evented() if engine has no eventable.
                // This looks like a bad idea, but the only engine that has
                // no eventable is the sim engine, and for that engine,
                // evented() is essentially a no-op.
                engine.borrow_mut().evented()?;
            }
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature = "dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                .iter()
                .filter(|pfd| pfd.revents != 0)
            {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) =
                        libstratis::dbus_api::handle(&dbus_conn, &item, &mut tree, &dbus_context)
                    {
                        print_err(&From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };

        // TODO: refine this behavior.
        // Different behaviors may be indicated, depending on the value of
        // errno when return value is -1.
        if r < 0 {
            return Err(StratisError::Error(format!(
                "poll command failed: number of fds: {}, timeout: {}",
                fds.len(),
                poll_timeout
            )));
        }
    }
}

fn main() {
    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(
            Arg::with_name("debug")
                .long("debug")
                .help("Print additional output for debugging"),
        )
        .arg(
            Arg::with_name("sim")
                .long("sim")
                .help("Use simulator engine"),
        )
        .get_matches();

    let result = trylock_pid_file()
        .and_then(|_pidfile| {
            Ok(initialize_log(matches.is_present("debug"))
                .expect("This is the first and only invocation of this method; it must succeed."))
        })
        .and_then(|_| run(&matches));
    if let Err(err) = result {
        print_err(&err);
        exit(1);
    } else {
        exit(0);
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use types::Value;
use binding::fixnum::{int_to_num, num_to_int};

use super::traits::Object;

#[derive(Debug, PartialEq)]
pub struct Fixnum {
    value: Value
}

impl Fixnum {
    pub fn new(num: i64) -> Self {
        Fixnum {
            value: int_to_num(num)
        }
    }

    pub fn to_i64(&self) -> i64 {
        num_to_int(self.value)
    }
}

impl From<Value> for Fixnum {
    fn from(value: Value) -> Self {
        Fixnum {
            value: value
        }
    }
}

impl Object for Fixnum {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Create documentation for Fixnum<commit_after>use std::convert::From;

use types::Value;
use binding::fixnum::{int_to_num, num_to_int};

use super::traits::Object;

/// `Fixnum`
#[derive(Debug, PartialEq)]
pub struct Fixnum {
    value: Value
}

impl Fixnum {
    /// Creates a new `Fixnum`
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Fixnum, VM};
    /// # VM::init();
    ///
    /// let fixnum = Fixnum::new(1);
    ///
    /// assert_eq!(fixnum.to_i64(), 1);
    /// ```
    pub fn new(num: i64) -> Self {
        Fixnum {
            value: int_to_num(num)
        }
    }

    /// Retrieves an `i64` value from `Fixnum`
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Fixnum, VM};
    /// # VM::init();
    ///
    /// let fixnum = Fixnum::new(1);
    ///
    /// assert_eq!(fixnum.to_i64(), 1);
    /// ```
    pub fn to_i64(&self) -> i64 {
        num_to_int(self.value)
    }
}

impl From<Value> for Fixnum {
    fn from(value: Value) -> Self {
        Fixnum {
            value: value
        }
    }
}

impl Object for Fixnum {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use binding::util;
use types;

use super::{array, class, object, string};

pub trait RawObject : From<types::rb_value> {
    fn value(&self) -> types::rb_value;

    fn as_object(&self) -> object::Object {
        object::Object::from(self.value())
    }

    fn as_array(&self) -> array::Array {
        array::Array::from(self.value())
    }

    fn as_class(&self) -> class::Class {
        class::Class::from(self.value())
    }

    fn as_string(&self) -> string::RString {
        string::RString::from(self.value())
    }

    fn send(&self, method: &str, arguments: Vec<object::Object>) -> object::Object {
        let arguments = arguments.iter().map(|object| object.value()).collect();
        let result = util::call_method(self.value(), method, arguments);

        object::Object::from(result)
    }
}
<commit_msg>Implement RawObject to_hash()<commit_after>use std::convert::From;

use binding::util;
use types;

use super::{array, class, hash, object, string};

pub trait RawObject : From<types::rb_value> {
    fn value(&self) -> types::rb_value;

    fn as_array(&self) -> array::Array {
        array::Array::from(self.value())
    }

    fn as_class(&self) -> class::Class {
        class::Class::from(self.value())
    }

    fn as_hash(&self) -> hash::Hash {
        hash::Hash::from(self.value())
    }

    fn as_object(&self) -> object::Object {
        object::Object::from(self.value())
    }

    fn as_string(&self) -> string::RString {
        string::RString::from(self.value())
    }

    fn send(&self, method: &str, arguments: Vec<object::Object>) -> object::Object {
        let arguments = arguments.iter().map(|object| object.value()).collect();
        let result = util::call_method(self.value(), method, arguments);

        object::Object::from(result)
    }
}
<|endoftext|>