<commit_before>use compact::{CDict, CVec, CHashMap};
use kay::{ID, ActorSystem, Fate, World};
use kay::swarm::{Swarm, SubActor};
use stagemaster::geometry::AnyShape;
use descartes::Band;
use super::lane::{Lane, TransferLane};
use super::connectivity::{Interaction, InteractionKind, OverlapKind};

pub mod trip;

#[derive(Compact, Clone, Default)]
pub struct PathfindingInfo {
    pub as_destination: Option<Destination>,
    pub hops_from_landmark: u8,
    pub learned_landmark_from: Option<ID>,
    pub routes: CHashMap<Destination, RoutingInfo>,
    pub routes_changed: bool,
    pub tell_to_forget_next_tick: CVec<Destination>,
    pub query_routes_next_tick: bool,
    pub routing_timeout: u16,
}

#[derive(Copy, Clone, PartialEq, Eq, Default, Hash, Debug)]
pub struct Destination {
    pub landmark: ID,
    pub node: ID,
}

impl Destination {
    fn landmark(landmark: ID) -> Self {
        Destination { landmark: landmark, node: landmark }
    }
    pub fn is_landmark(&self) -> bool {
        self.landmark == self.node
    }
    pub fn landmark_destination(&self) -> Self {
        Self::landmark(self.landmark)
    }
}

#[derive(Copy, Clone, Default, Debug)]
pub struct RoutingInfo {
    pub outgoing_idx: u8,
    pub distance: f32,
    distance_hops: u8,
    learned_from: ID,
    fresh: bool,
}

use stagemaster::{UserInterface, AddInteractable};
const DEBUG_CARS_ON_LANES: bool = false;

pub fn on_build(lane: &mut Lane, world: &mut World) {
    lane.pathfinding.as_destination = None;
    if DEBUG_CARS_ON_LANES {
        world.send_to_id_of::<UserInterface, _>(AddInteractable(
            lane.id(),
            AnyShape::Band(
                Band::new(lane.construction.path.clone(), 3.0),
            ),
            5,
        ));
    }
}

pub fn on_connect(lane: &mut Lane) {
    lane.pathfinding.routing_timeout = ROUTING_TIMEOUT_AFTER_CHANGE;
}

pub fn on_disconnect(lane: &mut Lane, disconnected_id: ID) {
    let new_routes = lane.pathfinding
        .routes
        .pairs()
        .filter_map(|(destination, route)| if route.learned_from ==
            disconnected_id
        {
            None
        } else {
            Some((*destination, *route))
        })
        .collect();
    lane.pathfinding.routes = new_routes;
    lane.pathfinding.routes_changed = true;
    lane.pathfinding.query_routes_next_tick = true;
}

const MIN_LANDMARK_INCOMING: usize = 3;
const ROUTING_TIMEOUT_AFTER_CHANGE: u16 = 15;

pub fn tick(lane: &mut Lane, world: &mut World) {
    if let Some(as_destination) = lane.pathfinding.as_destination {
        for successor in successors(lane) {
            world.send(
                successor,
                JoinLandmark {
                    from: lane.id(),
                    join_as: Destination {
                        landmark: as_destination.landmark,
                        node: successor,
                    },
                    hops_from_landmark: lane.pathfinding.hops_from_landmark + 1,
                },
            )
        }
    } else if !lane.connectivity.on_intersection &&
               predecessors(lane).count() >= MIN_LANDMARK_INCOMING
    {
        lane.pathfinding = PathfindingInfo {
            as_destination: Some(Destination::landmark(lane.id())),
            hops_from_landmark: 0,
            learned_landmark_from: Some(lane.id()),
            routes: CHashMap::new(),
            routes_changed: true,
            query_routes_next_tick: false,
            tell_to_forget_next_tick: CVec::new(),
            routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE,
        }
    }

    if lane.pathfinding.routing_timeout > 0 {
        lane.pathfinding.routing_timeout -= 1;
    } else {
        if lane.pathfinding.query_routes_next_tick {
            for successor in successors(lane) {
                world.send(
                    successor,
                    QueryRoutes { requester: lane.id(), is_transfer: false },
                );
            }
            lane.pathfinding.query_routes_next_tick = false;
        }

        if !lane.pathfinding.tell_to_forget_next_tick.is_empty() {
            for (_, predecessor, _) in predecessors(lane) {
                world.send(
                    predecessor,
                    ForgetRoutes {
                        forget: lane.pathfinding.tell_to_forget_next_tick.clone(),
                        from: lane.id(),
                    },
                )
            }
            lane.pathfinding.tell_to_forget_next_tick.clear();
        }

        if lane.pathfinding.routes_changed {
            for (_, predecessor, is_transfer) in predecessors(lane) {
                let self_cost = if is_transfer {
                    0.0
                } else {
                    lane.construction.length
                };
                world.send(
                    predecessor,
                    ShareRoutes {
                        new_routes: lane.pathfinding
                            .routes
                            .pairs()
                            .filter_map(|(&destination,
                              &RoutingInfo { distance, distance_hops, .. })| {
                                if true
                                // fresh
                                {
                                    Some((destination, (distance + self_cost, distance_hops + 1)))
                                } else {
                                    None
                                }
                            })
                            .chain(
                                if lane.connectivity.on_intersection {
                                    None
                                } else {
                                    lane.pathfinding
                                        .as_destination
                                        .map(|destination| (destination, (self_cost, 0)))
                                },
                            )
                            .collect(),
                        from: lane.id(),
                    },
                );
            }
            for routing_info in lane.pathfinding.routes.values_mut() {
                routing_info.fresh = false;
            }
            lane.pathfinding.routes_changed = false;
        }
    }
}

#[allow(needless_lifetimes)]
fn successors<'a>(lane: &'a Lane) -> impl Iterator<Item = ID> + 'a {
    lane.connectivity.interactions.iter().filter_map(
        |interaction| {
            match *interaction {
                Interaction {
                    partner_lane,
                    kind: InteractionKind::Overlap { kind: OverlapKind::Transfer, .. },
                    ..
                } |
                Interaction {
                    partner_lane,
                    kind: InteractionKind::Next { .. },
                    ..
                } => Some(partner_lane),
                _ => None,
            }
        },
    )
}

#[allow(needless_lifetimes)]
fn predecessors<'a>(lane: &'a Lane) -> impl Iterator<Item = (u8, ID, bool)> + 'a {
    lane.connectivity
        .interactions
        .iter()
        .enumerate()
        .filter_map(|(i, interaction)| match *interaction {
            Interaction {
                partner_lane,
                kind: InteractionKind::Overlap { kind: OverlapKind::Transfer, .. },
                ..
            } => Some((i as u8, partner_lane, true)),
            Interaction {
                partner_lane,
                kind: InteractionKind::Previous { .. },
                ..
            } => Some((i as u8, partner_lane, false)),
            _ => None,
        })
}

#[derive(Copy, Clone)]
pub struct JoinLandmark {
    from: ID,
    join_as: Destination,
    hops_from_landmark: u8,
}

const IDEAL_LANDMARK_RADIUS: u8 = 3;

pub fn setup(system: &mut ActorSystem) {
    system.extend(Swarm::<Lane>::subactors(|mut each_lane| {
        each_lane.on(|&JoinLandmark { join_as, hops_from_landmark, from },
         lane,
         _| {
            let join = lane.pathfinding
                .as_destination
                .map(|self_destination| {
                    join_as != self_destination &&
                        (if self_destination.is_landmark() {
                             hops_from_landmark < IDEAL_LANDMARK_RADIUS &&
                                 join_as.landmark.sub_actor_id < lane.id().sub_actor_id
                         } else {
                             hops_from_landmark < lane.pathfinding.hops_from_landmark ||
                                 lane.pathfinding
                                     .learned_landmark_from
                                     .map(|learned_from| learned_from == from)
                                     .unwrap_or(false)
                         })
                })
                .unwrap_or(true);
            if join {
                let tell_to_forget_next_tick = lane.pathfinding
                    .routes
                    .keys()
                    .cloned()
                    .chain(lane.pathfinding.as_destination.into_iter())
                    .collect();
                lane.pathfinding = PathfindingInfo {
                    as_destination: Some(join_as),
                    learned_landmark_from: Some(from),
                    hops_from_landmark: hops_from_landmark,
                    routes: CHashMap::new(),
                    routes_changed: true,
                    query_routes_next_tick: true,
                    tell_to_forget_next_tick: tell_to_forget_next_tick,
                    routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE,
                };
            }
            Fate::Live
        });

        each_lane.on(|&QueryRoutes { requester, is_transfer }, lane, world| {
            let self_cost = if is_transfer {
                0.0
            } else {
                lane.construction.length
            };
            world.send(
                requester,
                ShareRoutes {
                    new_routes: lane.pathfinding
                        .routes
                        .pairs()
                        .map(|(&destination,
                          &RoutingInfo { distance, distance_hops, .. })| {
                            (destination, (distance + self_cost, distance_hops + 1))
                        })
                        .chain(if lane.connectivity.on_intersection {
                            None
                        } else {
                            lane.pathfinding.as_destination.map(|destination| {
                                (destination, (self_cost, 0))
                            })
                        })
                        .collect(),
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_lane.on(|&ShareRoutes { ref new_routes, from }, lane, _| {
            if let Some(from_interaction_idx) =
                lane.connectivity.interactions.iter().position(
                    |interaction| {
                        interaction.partner_lane == from
                    },
                )
            {
                for (&destination, &(new_distance, new_distance_hops)) in new_routes.pairs() {
                    if destination.is_landmark() || new_distance_hops <= IDEAL_LANDMARK_RADIUS ||
                        lane.pathfinding
                            .as_destination
                            .map(|self_dest| self_dest.landmark == destination.landmark)
                            .unwrap_or(false)
                    {
                        let insert = lane.pathfinding
                            .routes
                            .get_mru(destination)
                            .map(|&RoutingInfo { distance, .. }| new_distance < distance)
                            .unwrap_or(true);
                        if insert {
                            lane.pathfinding.routes.insert(
                                destination,
                                RoutingInfo {
                                    distance: new_distance,
                                    distance_hops: new_distance_hops,
                                    outgoing_idx: from_interaction_idx as u8,
                                    learned_from: from,
                                    fresh: true,
                                },
                            );
                            lane.pathfinding.routes_changed = true;
                        }
                    }
                }
            } else {
                println!("{:?} not yet connected to {:?}", lane.id(), from);
            }
            Fate::Live
        });

        each_lane.on(|&ForgetRoutes { ref forget, from }, lane, _| {
            let mut forgotten = CVec::<Destination>::new();
            for destination_to_forget in forget.iter() {
                let forget = if let Some(routing_info) =
                    lane.pathfinding.routes.get(*destination_to_forget)
                {
                    routing_info.learned_from == from
                } else {
                    false
                };
                if forget {
                    lane.pathfinding.routes.remove(*destination_to_forget);
                    if destination_to_forget.is_landmark() {
                        lane.microtraffic.cars.retain(|car| {
                            car.destination.landmark != destination_to_forget.landmark
                        })
                    } else {
                        lane.microtraffic.cars.retain(|car| {
                            &car.destination != destination_to_forget
                        })
                    }
                    forgotten.push(*destination_to_forget);
                }
            }
            lane.pathfinding.tell_to_forget_next_tick = forgotten;
            Fate::Live
        });

        each_lane.on(|&QueryAsDestination { requester }, lane, world| {
            world.send(
                requester,
                TellAsDestination {
                    id: lane.id(),
                    as_destination: lane.pathfinding.as_destination,
                },
            );
            Fate::Live
        })
    }));

    system.extend(Swarm::<TransferLane>::subactors(|mut each_t_lane| {
        each_t_lane.on(|&JoinLandmark { join_as, hops_from_landmark, from },
         lane,
         world| {
            world.send(
                lane.other_side(from),
                JoinLandmark {
                    join_as: Destination {
                        landmark: join_as.landmark,
                        node: lane.other_side(from),
                    },
                    hops_from_landmark: hops_from_landmark,
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_t_lane.on(|&QueryRoutes { requester, .. }, lane, world| {
            world.send(
                lane.other_side(requester),
                QueryRoutes { requester: lane.id(), is_transfer: true },
            );
            Fate::Live
        });

        each_t_lane.on(|&ShareRoutes { ref new_routes, from }, lane, world| {
            world.send(
                lane.other_side(from),
                ShareRoutes {
                    new_routes: new_routes
                        .pairs()
                        .map(|(&destination, &(distance, hops))| {
                            (destination, (
                                distance +
                                    if from ==
                                        lane.connectivity
                                            .left
                                            .expect("should have left")
                                            .0
                                    {
                                        LANE_CHANGE_COST_RIGHT
                                    } else {
                                        LANE_CHANGE_COST_LEFT
                                    },
                                hops,
                            ))
                        })
                        .collect(),
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_t_lane.on(|&ForgetRoutes { ref forget, from }, lane, world| {
            world.send(
                lane.other_side(from),
                ForgetRoutes { forget: forget.clone(), from: lane.id() },
            );
            Fate::Live
        })
    }));

    trip::setup(system);
}

#[derive(Copy, Clone)]
pub struct QueryRoutes {
    requester: ID,
    is_transfer: bool,
}

#[derive(Compact, Clone)]
pub struct ShareRoutes {
    new_routes: CDict<Destination, (f32, u8)>,
    from: ID,
}

const LANE_CHANGE_COST_LEFT: f32 = 5.0;
const LANE_CHANGE_COST_RIGHT: f32 = 3.0;

#[derive(Compact, Clone)]
pub struct ForgetRoutes {
    forget: CVec<Destination>,
    from: ID,
}

#[derive(Copy, Clone)]
pub struct QueryAsDestination {
    requester: ID,
}
#[derive(Copy, Clone)]
pub struct TellAsDestination {
    id: ID,
    as_destination: Option<Destination>,
}
<commit_msg>default is not needed for Destination<commit_after>use compact::{CDict, CVec, CHashMap};
use kay::{ID, ActorSystem, Fate, World};
use kay::swarm::{Swarm, SubActor};
use stagemaster::geometry::AnyShape;
use descartes::Band;
use super::lane::{Lane, TransferLane};
use super::connectivity::{Interaction, InteractionKind, OverlapKind};

pub mod trip;

#[derive(Compact, Clone, Default)]
pub struct PathfindingInfo {
    pub as_destination: Option<Destination>,
    pub hops_from_landmark: u8,
    pub learned_landmark_from: Option<ID>,
    pub routes: CHashMap<Destination, RoutingInfo>,
    pub routes_changed: bool,
    pub tell_to_forget_next_tick: CVec<Destination>,
    pub query_routes_next_tick: bool,
    pub routing_timeout: u16,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Destination {
    pub landmark: ID,
    pub node: ID,
}

impl Destination {
    fn landmark(landmark: ID) -> Self {
        Destination { landmark: landmark, node: landmark }
    }
    pub fn is_landmark(&self) -> bool {
        self.landmark == self.node
    }
    pub fn landmark_destination(&self) -> Self {
        Self::landmark(self.landmark)
    }
}

#[derive(Copy, Clone, Default, Debug)]
pub struct RoutingInfo {
    pub outgoing_idx: u8,
    pub distance: f32,
    distance_hops: u8,
    learned_from: ID,
    fresh: bool,
}

use stagemaster::{UserInterface, AddInteractable};
const DEBUG_CARS_ON_LANES: bool = false;

pub fn on_build(lane: &mut Lane, world: &mut World) {
    lane.pathfinding.as_destination = None;
    if DEBUG_CARS_ON_LANES {
        world.send_to_id_of::<UserInterface, _>(AddInteractable(
            lane.id(),
            AnyShape::Band(
                Band::new(lane.construction.path.clone(), 3.0),
            ),
            5,
        ));
    }
}

pub fn on_connect(lane: &mut Lane) {
    lane.pathfinding.routing_timeout = ROUTING_TIMEOUT_AFTER_CHANGE;
}

pub fn on_disconnect(lane: &mut Lane, disconnected_id: ID) {
    let new_routes = lane.pathfinding
        .routes
        .pairs()
        .filter_map(|(destination, route)| if route.learned_from ==
            disconnected_id
        {
            None
        } else {
            Some((*destination, *route))
        })
        .collect();
    lane.pathfinding.routes = new_routes;
    lane.pathfinding.routes_changed = true;
    lane.pathfinding.query_routes_next_tick = true;
}

const MIN_LANDMARK_INCOMING: usize = 3;
const ROUTING_TIMEOUT_AFTER_CHANGE: u16 = 15;

pub fn tick(lane: &mut Lane, world: &mut World) {
    if let Some(as_destination) = lane.pathfinding.as_destination {
        for successor in successors(lane) {
            world.send(
                successor,
                JoinLandmark {
                    from: lane.id(),
                    join_as: Destination {
                        landmark: as_destination.landmark,
                        node: successor,
                    },
                    hops_from_landmark: lane.pathfinding.hops_from_landmark + 1,
                },
            )
        }
    } else if !lane.connectivity.on_intersection &&
               predecessors(lane).count() >= MIN_LANDMARK_INCOMING
    {
        lane.pathfinding = PathfindingInfo {
            as_destination: Some(Destination::landmark(lane.id())),
            hops_from_landmark: 0,
            learned_landmark_from: Some(lane.id()),
            routes: CHashMap::new(),
            routes_changed: true,
            query_routes_next_tick: false,
            tell_to_forget_next_tick: CVec::new(),
            routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE,
        }
    }

    if lane.pathfinding.routing_timeout > 0 {
        lane.pathfinding.routing_timeout -= 1;
    } else {
        if lane.pathfinding.query_routes_next_tick {
            for successor in successors(lane) {
                world.send(
                    successor,
                    QueryRoutes { requester: lane.id(), is_transfer: false },
                );
            }
            lane.pathfinding.query_routes_next_tick = false;
        }

        if !lane.pathfinding.tell_to_forget_next_tick.is_empty() {
            for (_, predecessor, _) in predecessors(lane) {
                world.send(
                    predecessor,
                    ForgetRoutes {
                        forget: lane.pathfinding.tell_to_forget_next_tick.clone(),
                        from: lane.id(),
                    },
                )
            }
            lane.pathfinding.tell_to_forget_next_tick.clear();
        }

        if lane.pathfinding.routes_changed {
            for (_, predecessor, is_transfer) in predecessors(lane) {
                let self_cost = if is_transfer {
                    0.0
                } else {
                    lane.construction.length
                };
                world.send(
                    predecessor,
                    ShareRoutes {
                        new_routes: lane.pathfinding
                            .routes
                            .pairs()
                            .filter_map(|(&destination,
                              &RoutingInfo { distance, distance_hops, .. })| {
                                if true
                                // fresh
                                {
                                    Some((destination, (distance + self_cost, distance_hops + 1)))
                                } else {
                                    None
                                }
                            })
                            .chain(
                                if lane.connectivity.on_intersection {
                                    None
                                } else {
                                    lane.pathfinding
                                        .as_destination
                                        .map(|destination| (destination, (self_cost, 0)))
                                },
                            )
                            .collect(),
                        from: lane.id(),
                    },
                );
            }
            for routing_info in lane.pathfinding.routes.values_mut() {
                routing_info.fresh = false;
            }
            lane.pathfinding.routes_changed = false;
        }
    }
}

#[allow(needless_lifetimes)]
fn successors<'a>(lane: &'a Lane) -> impl Iterator<Item = ID> + 'a {
    lane.connectivity.interactions.iter().filter_map(
        |interaction| {
            match *interaction {
                Interaction {
                    partner_lane,
                    kind: InteractionKind::Overlap { kind: OverlapKind::Transfer, .. },
                    ..
                } |
                Interaction {
                    partner_lane,
                    kind: InteractionKind::Next { .. },
                    ..
                } => Some(partner_lane),
                _ => None,
            }
        },
    )
}

#[allow(needless_lifetimes)]
fn predecessors<'a>(lane: &'a Lane) -> impl Iterator<Item = (u8, ID, bool)> + 'a {
    lane.connectivity
        .interactions
        .iter()
        .enumerate()
        .filter_map(|(i, interaction)| match *interaction {
            Interaction {
                partner_lane,
                kind: InteractionKind::Overlap { kind: OverlapKind::Transfer, .. },
                ..
            } => Some((i as u8, partner_lane, true)),
            Interaction {
                partner_lane,
                kind: InteractionKind::Previous { .. },
                ..
            } => Some((i as u8, partner_lane, false)),
            _ => None,
        })
}

#[derive(Copy, Clone)]
pub struct JoinLandmark {
    from: ID,
    join_as: Destination,
    hops_from_landmark: u8,
}

const IDEAL_LANDMARK_RADIUS: u8 = 3;

pub fn setup(system: &mut ActorSystem) {
    system.extend(Swarm::<Lane>::subactors(|mut each_lane| {
        each_lane.on(|&JoinLandmark { join_as, hops_from_landmark, from },
         lane,
         _| {
            let join = lane.pathfinding
                .as_destination
                .map(|self_destination| {
                    join_as != self_destination &&
                        (if self_destination.is_landmark() {
                             hops_from_landmark < IDEAL_LANDMARK_RADIUS &&
                                 join_as.landmark.sub_actor_id < lane.id().sub_actor_id
                         } else {
                             hops_from_landmark < lane.pathfinding.hops_from_landmark ||
                                 lane.pathfinding
                                     .learned_landmark_from
                                     .map(|learned_from| learned_from == from)
                                     .unwrap_or(false)
                         })
                })
                .unwrap_or(true);
            if join {
                let tell_to_forget_next_tick = lane.pathfinding
                    .routes
                    .keys()
                    .cloned()
                    .chain(lane.pathfinding.as_destination.into_iter())
                    .collect();
                lane.pathfinding = PathfindingInfo {
                    as_destination: Some(join_as),
                    learned_landmark_from: Some(from),
                    hops_from_landmark: hops_from_landmark,
                    routes: CHashMap::new(),
                    routes_changed: true,
                    query_routes_next_tick: true,
                    tell_to_forget_next_tick: tell_to_forget_next_tick,
                    routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE,
                };
            }
            Fate::Live
        });

        each_lane.on(|&QueryRoutes { requester, is_transfer }, lane, world| {
            let self_cost = if is_transfer {
                0.0
            } else {
                lane.construction.length
            };
            world.send(
                requester,
                ShareRoutes {
                    new_routes: lane.pathfinding
                        .routes
                        .pairs()
                        .map(|(&destination,
                          &RoutingInfo { distance, distance_hops, .. })| {
                            (destination, (distance + self_cost, distance_hops + 1))
                        })
                        .chain(if lane.connectivity.on_intersection {
                            None
                        } else {
                            lane.pathfinding.as_destination.map(|destination| {
                                (destination, (self_cost, 0))
                            })
                        })
                        .collect(),
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_lane.on(|&ShareRoutes { ref new_routes, from }, lane, _| {
            if let Some(from_interaction_idx) =
                lane.connectivity.interactions.iter().position(
                    |interaction| {
                        interaction.partner_lane == from
                    },
                )
            {
                for (&destination, &(new_distance, new_distance_hops)) in new_routes.pairs() {
                    if destination.is_landmark() || new_distance_hops <= IDEAL_LANDMARK_RADIUS ||
                        lane.pathfinding
                            .as_destination
                            .map(|self_dest| self_dest.landmark == destination.landmark)
                            .unwrap_or(false)
                    {
                        let insert = lane.pathfinding
                            .routes
                            .get_mru(destination)
                            .map(|&RoutingInfo { distance, .. }| new_distance < distance)
                            .unwrap_or(true);
                        if insert {
                            lane.pathfinding.routes.insert(
                                destination,
                                RoutingInfo {
                                    distance: new_distance,
                                    distance_hops: new_distance_hops,
                                    outgoing_idx: from_interaction_idx as u8,
                                    learned_from: from,
                                    fresh: true,
                                },
                            );
                            lane.pathfinding.routes_changed = true;
                        }
                    }
                }
            } else {
                println!("{:?} not yet connected to {:?}", lane.id(), from);
            }
            Fate::Live
        });

        each_lane.on(|&ForgetRoutes { ref forget, from }, lane, _| {
            let mut forgotten = CVec::<Destination>::new();
            for destination_to_forget in forget.iter() {
                let forget = if let Some(routing_info) =
                    lane.pathfinding.routes.get(*destination_to_forget)
                {
                    routing_info.learned_from == from
                } else {
                    false
                };
                if forget {
                    lane.pathfinding.routes.remove(*destination_to_forget);
                    if destination_to_forget.is_landmark() {
                        lane.microtraffic.cars.retain(|car| {
                            car.destination.landmark != destination_to_forget.landmark
                        })
                    } else {
                        lane.microtraffic.cars.retain(|car| {
                            &car.destination != destination_to_forget
                        })
                    }
                    forgotten.push(*destination_to_forget);
                }
            }
            lane.pathfinding.tell_to_forget_next_tick = forgotten;
            Fate::Live
        });

        each_lane.on(|&QueryAsDestination { requester }, lane, world| {
            world.send(
                requester,
                TellAsDestination {
                    id: lane.id(),
                    as_destination: lane.pathfinding.as_destination,
                },
            );
            Fate::Live
        })
    }));

    system.extend(Swarm::<TransferLane>::subactors(|mut each_t_lane| {
        each_t_lane.on(|&JoinLandmark { join_as, hops_from_landmark, from },
         lane,
         world| {
            world.send(
                lane.other_side(from),
                JoinLandmark {
                    join_as: Destination {
                        landmark: join_as.landmark,
                        node: lane.other_side(from),
                    },
                    hops_from_landmark: hops_from_landmark,
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_t_lane.on(|&QueryRoutes { requester, .. }, lane, world| {
            world.send(
                lane.other_side(requester),
                QueryRoutes { requester: lane.id(), is_transfer: true },
            );
            Fate::Live
        });

        each_t_lane.on(|&ShareRoutes { ref new_routes, from }, lane, world| {
            world.send(
                lane.other_side(from),
                ShareRoutes {
                    new_routes: new_routes
                        .pairs()
                        .map(|(&destination, &(distance, hops))| {
                            (destination, (
                                distance +
                                    if from ==
                                        lane.connectivity
                                            .left
                                            .expect("should have left")
                                            .0
                                    {
                                        LANE_CHANGE_COST_RIGHT
                                    } else {
                                        LANE_CHANGE_COST_LEFT
                                    },
                                hops,
                            ))
                        })
                        .collect(),
                    from: lane.id(),
                },
            );
            Fate::Live
        });

        each_t_lane.on(|&ForgetRoutes { ref forget, from }, lane, world| {
            world.send(
                lane.other_side(from),
                ForgetRoutes { forget: forget.clone(), from: lane.id() },
            );
            Fate::Live
        })
    }));

    trip::setup(system);
}

#[derive(Copy, Clone)]
pub struct QueryRoutes {
    requester: ID,
    is_transfer: bool,
}

#[derive(Compact, Clone)]
pub struct ShareRoutes {
    new_routes: CDict<Destination, (f32, u8)>,
    from: ID,
}

const LANE_CHANGE_COST_LEFT: f32 = 5.0;
const LANE_CHANGE_COST_RIGHT: f32 = 3.0;

#[derive(Compact, Clone)]
pub struct ForgetRoutes {
    forget: CVec<Destination>,
    from: ID,
}

#[derive(Copy, Clone)]
pub struct QueryAsDestination {
    requester: ID,
}
#[derive(Copy, Clone)]
pub struct TellAsDestination {
    id: ID,
    as_destination: Option<Destination>,
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) -> bool {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
            return true
        }
        false
    }

    /// Decrements the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_up(&mut self) {
        let target_line = self.line-1;
        let new_position = Position{ line: target_line, offset: self.offset };

        // Don't even bother if the target line is negative.
        if target_line < 0 { return }

        // Try moving to the same offset on the line above, falling back to its EOL.
        if self.move_to(new_position) == false {
            let mut target_offset = 0;
            for (line_number, line) in self.data.borrow().to_string().lines().enumerate() {
                if line_number == target_line {
                    target_offset = line.len();
                }
            }
            self.move_to(Position{ line: target_line, offset: target_offset });
        }
    }

    /// Increments the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_down(&mut self) {
        let target_line = self.line+1;
        let new_position = Position{ line: target_line, offset: self.offset };

        // Try moving to the same offset on the line below, falling back to its EOL.
        if self.move_to(new_position) == false {
            let mut target_offset = 0;
            for (line_number, line) in self.data.borrow().to_string().lines().enumerate() {
                if line_number == target_line {
                    target_offset = line.len();
                }
            }
            self.move_to(Position{ line: target_line, offset: target_offset });
        }
    }

    /// Decrements the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_left(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset-1 };
        self.move_to(new_position);
    }

    /// Increments the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_right(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset+1 };
        self.move_to(new_position);
    }
}

#[cfg(test)]
mod tests {
    use super::Cursor;
    use super::super::gap_buffer;
    use super::super::Position;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn move_up_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("This is a test.\nAnother line that is longer.".to_string())));
        let position = Position{ line: 1, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_up();
        assert_eq!(cursor.line, 0);
        assert_eq!(cursor.offset, 15);
    }

    #[test]
    fn move_down_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("Another line that is longer.\nThis is a test.".to_string())));
        let position = Position{ line: 0, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_down();
        assert_eq!(cursor.line, 1);
        assert_eq!(cursor.offset, 15);
    }
}
<commit_msg>Add a move_to_start_of_line method to cursor type.<commit_after>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) -> bool {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
            return true
        }
        false
    }

    /// Decrements the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_up(&mut self) {
        let target_line = self.line-1;
        let new_position = Position{ line: target_line, offset: self.offset };

        // Don't even bother if the target line is negative.
        if target_line < 0 { return }

        // Try moving to the same offset on the line above, falling back to its EOL.
        if self.move_to(new_position) == false {
            let mut target_offset = 0;
            for (line_number, line) in self.data.borrow().to_string().lines().enumerate() {
                if line_number == target_line {
                    target_offset = line.len();
                }
            }
            self.move_to(Position{ line: target_line, offset: target_offset });
        }
    }

    /// Increments the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_down(&mut self) {
        let target_line = self.line+1;
        let new_position = Position{ line: target_line, offset: self.offset };

        // Try moving to the same offset on the line below, falling back to its EOL.
        if self.move_to(new_position) == false {
            let mut target_offset = 0;
            for (line_number, line) in self.data.borrow().to_string().lines().enumerate() {
                if line_number == target_line {
                    target_offset = line.len();
                }
            }
            self.move_to(Position{ line: target_line, offset: target_offset });
        }
    }

    /// Decrements the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_left(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset-1 };
        self.move_to(new_position);
    }

    /// Increments the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_right(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset+1 };
        self.move_to(new_position);
    }

    /// Sets the cursor offset to 0: the start of the current line.
    pub fn move_to_start_of_line(&mut self) {
        let new_position = Position{ line: self.line, offset: 0 };
        self.move_to(new_position);
    }
}

#[cfg(test)]
mod tests {
    use super::Cursor;
    use super::super::gap_buffer;
    use super::super::Position;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn move_up_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("This is a test.\nAnother line that is longer.".to_string())));
        let position = Position{ line: 1, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_up();
        assert_eq!(cursor.line, 0);
        assert_eq!(cursor.offset, 15);
    }

    #[test]
    fn move_down_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("Another line that is longer.\nThis is a test.".to_string())));
        let position = Position{ line: 0, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_down();
        assert_eq!(cursor.line, 1);
        assert_eq!(cursor.offset, 15);
    }

    #[test]
    fn move_to_start_of_line_sets_offset_to_zero() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("This is a test.\nAnother line.".to_string())));
        let position = Position{ line: 1, offset: 5 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_to_start_of_line();
        assert_eq!(cursor.line, 1);
        assert_eq!(cursor.offset, 0);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use base64;
use serde_json;
use serde_json::Value as Json;

use Component;
use error::Error;

#[derive(Debug, Default, PartialEq)]
pub struct Claims {
    pub reg: Registered,
    pub private: BTreeMap<String, Json>,
}

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Registered {
    pub iss: Option<String>,
    pub sub: Option<String>,
    pub aud: Option<String>,
    pub exp: Option<u64>,
    pub nbf: Option<u64>,
    pub iat: Option<u64>,
    pub jti: Option<String>,
}

/// JWT Claims. Registered claims are directly accessible via the `Registered`
/// struct embedded, while private fields are a map that contains `Json`
/// values.
impl Claims {
    pub fn new(reg: Registered) -> Claims {
        Claims {
            reg: reg,
            private: BTreeMap::new(),
        }
    }
}

impl Component for Claims {
    fn from_base64(raw: &str) -> Result<Claims, Error> {
        let data = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
        let s = String::from_utf8(data)?;
        let tree = match serde_json::from_str(&*s)? {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        const FIELDS: [&'static str; 7] = ["iss", "sub", "aud", "exp", "nbf", "iat", "jti"];

        let (_, pri): (BTreeMap<_, _>, BTreeMap<_, _>) = tree.into_iter()
            .partition(|&(ref key, _)| FIELDS.iter().any(|f| f == key));

        let reg_claims: Registered = serde_json::from_str(&*s)?;

        Ok(Claims {
            reg: reg_claims,
            private: pri,
        })
    }

    fn to_base64(&self) -> Result<String, Error> {
        let mut json_claims = match serde_json::to_value(&self.reg)? {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        json_claims.extend(self.private.clone());

        let s = serde_json::to_string(&json_claims)?;
        let enc = base64::encode_config(&*s, base64::URL_SAFE_NO_PAD);
        Ok(enc)
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use claims::{Claims, Registered};
    use Component;
    use serde_json::Value;

    // {"iss":"mikkyang.com","exp":1302319100,"custom_claim":true}
    const ENCODED_PAYLOAD: &'static str = "eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";

    #[test]
    fn registered_claims() {
        let claims = Claims::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.reg.iss.unwrap(), "mikkyang.com");
        assert_eq!(claims.reg.exp.unwrap(), 1302319100);
    }

    #[test]
    fn private_claims() {
        let claims = Claims::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.private["custom_claim"], Value::Bool(true));
    }

    #[test]
    fn roundtrip() {
        let mut claims: Claims = Default::default();
        claims.reg.iss = Some("mikkyang.com".into());
        claims.reg.exp = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, Claims::from_base64(&*enc).unwrap());
    }
}
<commit_msg>Use serde flatten instead of own logic<commit_after>use std::collections::BTreeMap;
use serde_json::Value as Json;

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Claims {
    #[serde(flatten)]
    pub reg: Registered,
    #[serde(flatten)]
    pub private: BTreeMap<String, Json>,
}

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Registered {
    pub iss: Option<String>,
    pub sub: Option<String>,
    pub aud: Option<String>,
    pub exp: Option<u64>,
    pub nbf: Option<u64>,
    pub iat: Option<u64>,
    pub jti: Option<String>,
}

/// JWT Claims. Registered claims are directly accessible via the `Registered`
/// struct embedded, while private fields are a map that contains `Json`
/// values.
impl Claims {
    pub fn new(reg: Registered) -> Claims {
        Claims {
            reg: reg,
            private: BTreeMap::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use claims::Claims;
    use Component;
    use serde_json::Value;

    // {"iss":"mikkyang.com","exp":1302319100,"custom_claim":true}
    const ENCODED_PAYLOAD: &'static str = "eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";

    #[test]
    fn registered_claims() {
        let claims = Claims::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.reg.iss.unwrap(), "mikkyang.com");
        assert_eq!(claims.reg.exp.unwrap(), 1302319100);
    }

    #[test]
    fn private_claims() {
        let claims = Claims::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.private["custom_claim"], Value::Bool(true));
    }

    #[test]
    fn roundtrip() {
        let mut claims: Claims = Default::default();
        claims.reg.iss = Some("mikkyang.com".into());
        claims.reg.exp = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, Claims::from_base64(&*enc).unwrap());
    }
}
<|endoftext|>


<commit_before>use clientbound::ClientboundPacket;
use connection::Connection;
use errors::Result;
use json::AuthenticationResponse;
use serverbound::ServerboundPacket;
use {ClientState, PROTOCOL_VERSION, mojang, serverbound, utils};

use std::{thread, time};

/// Represents a single client connection to a Server.
pub struct Client {
    conn: Connection<ClientboundPacket, ServerboundPacket>,
    auto_handle: bool,
    hide_handled: bool,
}
impl Client {
    /// Attempt open the tcp connection to the given host and port, and
    /// nothing more. If you use this you must then send all subsequent
    /// packets manually to authenticate and so on.
    pub fn connect_tcp(host: &str, port: u16) -> Result<Self> {
        Ok(Client {
               conn: Connection::connect_tcp(host, port)?,
               auto_handle: false,
               hide_handled: false,
           })
    }

    /// Attempt to connect to the server at the given host and port,
    /// completing the usual steps for an unauthenticated login.
    ///
    /// In most cases this is what you will want for offline/local servers
    /// and singleplayer. This will establish an unencrypted connection
    /// to the server.
    ///
    /// The username is the Minecraft username, and not the Mojang username,
    /// (i.e. NOT the email address for migrated accounts.)
    ///
    /// This will set auto_handle and hide_handled to true.
    ///
    /// This will return Ok(Client) on receival of a PlayerAbilities packet,
    /// but note that the PlayerAbilities packet and all packets received before
    /// it will not be available for consumers. If you need any of those
    /// packets, you will want to do the authentication manually.
    ///
    /// This function will time out after 30 seconds (theoretical absolute worst
    /// case 60 seconds.)
    pub fn connect_unauthenticated(host: &str,
                                   port: u16,
                                   username: &str)
                                   -> Result<Self> {

        let timeout = time::Instant::now();
        let mut client = Client::connect_tcp(host, port)?;
        client.set_auto_handle(true);
        client.set_hide_handled(true);
        let handshake = serverbound::Handshake::new(PROTOCOL_VERSION,
                                                    host.to_string(),
                                                    port,
                                                    2);
        let loginstart = serverbound::LoginStart::new(username.to_string());
        client.send(handshake)?;
        client.set_clientstate(ClientState::Login);
        client.send(loginstart)?;

        /* Now we wait for the PlayerAbilities packet from the server */
        'wait: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for LoginSuccess");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::PlayerAbilities(..)) => break 'wait,
                Some(ClientboundPacket::EncryptionRequest(..)) => {
                    bail!("connect_unauthenticated got EncryptionRequest");
                },
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        Ok(client)
    }

    /// Authenticate with Mojang, and then connect to the server at the
    /// given host and port. In most cases this is what you will want to use
    /// to connect to online servers.
    ///
    /// This will establish an encrypted connection to the server.
    ///
    /// Requires that you've already authenticated with Mojang, e.g. by calling
    /// yggdrasil::authenticate
    ///
    /// This will set auto_handle and hide_handled to true.
    ///
    /// This will return Ok(Client) on receival of a PlayerAbilities packet,
    /// but note that the PlayerAbilities packet and all packets received before
    /// it will not be available for consumers. If you need any of those
    /// packets, you will want to do the authentication manually.
    ///
    /// This function will time out after 30 seconds (theoretical absolute worst
    /// case 60 seconds.)
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use ozelot::{mojang, Client};
    /// let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
    ///                                      "my_password".to_string())
    ///     .perform().unwrap();
    /// let mut client = Client::connect_authenticated("minecraft.example.com",
    /// 25565,
    /// &auth).unwrap();
    /// ```
    pub fn connect_authenticated(host: &str,
                                 port: u16,
                                 auth: &AuthenticationResponse)
                                 -> Result<Self> {

        let timeout = time::Instant::now();
        let mut client = Client::connect_tcp(host, port)?;
        client.set_auto_handle(true);
        client.set_hide_handled(true);
        let handshake = serverbound::Handshake::new(PROTOCOL_VERSION,
                                                    host.to_string(),
                                                    port,
                                                    2);
        let loginstart =
            serverbound::LoginStart::new(auth.selectedProfile.name.clone());
        client.send(handshake)?;
        client.set_clientstate(ClientState::Login);
        client.send(loginstart)?;

        /* Here we wait for a LoginSuccess/EncryptionRequest packet */
        'wait: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for LoginSuccess/EncryptionRequest");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::LoginSuccess(..)) => {
                    bail!("Logged in unauthenticated")
                },
                Some(ClientboundPacket::EncryptionRequest(ref p)) => {
                    let shared_secret = utils::create_shared_secret();

                    mojang::SessionJoin::new(auth.accessToken.clone(),
                                             auth.selectedProfile.id.clone(),
                                             p.get_server_id(),
                                             &shared_secret,
                                             p.get_public_key())
                            .perform()?;

                    let encryptionresponse
                            = serverbound::EncryptionResponse::new_unencrypted(
                                &p.get_public_key(),
                                &shared_secret,
                                &p.get_verify_token())?;
                    client.send(encryptionresponse)?;
                    client.enable_encryption(&shared_secret);

                    break 'wait;
                },
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        /* Now we wait for the PlayerAbilities packet from the server */
        'wait2: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for PlayerAbilities packet");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::PlayerAbilities(..)) => break 'wait2,
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        Ok(client)
    }

    /// Try to read some packets from the server.
    ///
    /// This function is nonblocking.
    pub fn read(&mut self) -> Result<Vec<ClientboundPacket>> {
        self.update_inbuf()?;

        let mut ret = Vec::new();
        loop {
            let packet = self.read_packet()?;
            /* push = whether to push the packet to ret */
            let mut push = match &packet {
                &Some(ClientboundPacket::LoginSuccess(_)) => false,
                &Some(ClientboundPacket::SetCompression(_)) => false,
                &Some(ClientboundPacket::KeepAlive(_)) => false,
                &Some(_) => true,
                &None => break,
            };
            if self.hide_handled == false || self.auto_handle == false {
                push = true;
            }

            if push {
                ret.push(packet
                         .expect("unreachable packet = None in client.read()"));
            }
        }

        Ok(ret)
    }

    /// Send the given packet
    ///
    /// This adds the packet to the outgoing buffer, and sends as much as is
    /// possible. Returns the length of the outgoing buffer. If this is greater
    /// than 0, you will need to call write() to send the remaining data.
    pub fn send(&mut self, packet: ServerboundPacket) -> Result<usize> {
        self.conn.send(packet)
    }

    /// Write from the outgoing buffer to the TcpStream
    ///
    /// Returns the amount of bytes written.
    pub fn write(&mut self) -> Result<usize> {
        self.conn.write()
    }

    /// Whether to automatically handle: KeepAlive, LoginSuccess and
    /// SetCompression packets. Most clients won't need to manually deal with
    /// these.
    pub fn set_auto_handle(&mut self, new: bool) {
        self.auto_handle = new;
    }

    /// Whether or not to hide packets that have been handled by ozelot from the
    /// consumer of the library.
    ///
    /// E.g. KeepAlives that are automatically handled if auto_handle = true.
    pub fn set_hide_handled(&mut self, new: bool) {
        self.hide_handled = new;
    }

    /// Attempt to close this connection, disconnecting from the server.
    ///
    /// All future sends and reads to this connection will fail.
    pub fn close(&mut self) -> Result<()> {
        self.conn.close()
    }

    /// Change the client state of this connection
    pub fn set_clientstate(&mut self, new_state: ClientState) {
        self.conn.set_clientstate(new_state)
    }

    /// Enable encryption with the given key.
    ///
    /// It is an error to enable encryption if encryption has already been
    /// enabled.
    pub fn enable_encryption(&mut self, key: &[u8; 16]) {
        self.conn.enable_encryption(key)
    }

    /// Enable compression.
    ///
    /// It is generally an error to enable compression if compression has
    /// already been enabled.
    pub fn enable_compression(&mut self, threshold: usize) {
        self.conn.enable_compression(threshold)
    }

    /// Read from the TcpStream and update the incoming buffer.
    ///
    /// This is the only way to actually read from the TcpStream. Unless you
    /// know for sure you need to call this, then you do not need to call this.
    /// I.e. if you're just using client.read(), then you do not need to call
    /// this function.
    ///
    /// This function is nonblocking.
    pub fn update_inbuf(&mut self) -> Result<()> {
        self.conn.update_inbuf()
    }

    /// Read a single packet from the internal buffer.
    ///
    /// This is only really useful if you want finegrained control over the
    /// processing of packets, or if you want to manually authenticate with
    /// the server. In most cases, you'll want to just call client.read().
    ///
    /// You MUST be sure that client.update_inbuf() has been called before this,
    /// this function will not attempt to read from the TcpStream, only from the
    /// internal buffer.
    pub fn read_packet(&mut self) -> Result<Option<ClientboundPacket>> {
        let packet = self.conn.read_packet()?;

        if self.auto_handle {
            match &packet {
                &Some(ClientboundPacket::LoginSuccess(..)) => {
                    self.set_clientstate(ClientState::Play);
                },
                &Some(ClientboundPacket::SetCompression(ref p)) => {
                    self.enable_compression(*p.get_threshold() as usize);
                },
                &Some(ClientboundPacket::KeepAlive(ref p)) => {
                    let keepalive = serverbound::KeepAlive::new(*p.get_id());
                    self.send(keepalive)?;
                },
                _ => (),
            }
        }

        Ok(packet)
    }
}
<commit_msg>Add Client::from_tcpstream<commit_after>use clientbound::ClientboundPacket;
use connection::Connection;
use errors::Result;
use json::AuthenticationResponse;
use serverbound::ServerboundPacket;
use {ClientState, PROTOCOL_VERSION, mojang, serverbound, utils};

use std::{thread, time};
use std::net::TcpStream;

/// Represents a single client connection to a Server.
pub struct Client {
    conn: Connection<ClientboundPacket, ServerboundPacket>,
    auto_handle: bool,
    hide_handled: bool,
}
impl Client {
    /// Attempt open the tcp connection to the given host and port, and
    /// nothing more. If you use this you must then send all subsequent
    /// packets manually to authenticate and so on.
    pub fn connect_tcp(host: &str, port: u16) -> Result<Self> {
        Ok(Client {
               conn: Connection::connect_tcp(host, port)?,
               auto_handle: false,
               hide_handled: false,
           })
    }

    /// Create a new connection from an existing TcpStream
    pub fn from_tcpstream(stream: TcpStream) -> Result<Self> {
        Ok(Client {
            conn: Connection::from_tcpstream(stream)?,
            auto_handle: false,
            hide_handled: false,
        })
    }

    /// Attempt to connect to the server at the given host and port,
    /// completing the usual steps for an unauthenticated login.
    ///
    /// In most cases this is what you will want for offline/local servers
    /// and singleplayer. This will establish an unencrypted connection
    /// to the server.
    ///
    /// The username is the Minecraft username, and not the Mojang username,
    /// (i.e. NOT the email address for migrated accounts.)
    ///
    /// This will set auto_handle and hide_handled to true.
    ///
    /// This will return Ok(Client) on receival of a PlayerAbilities packet,
    /// but note that the PlayerAbilities packet and all packets received before
    /// it will not be available for consumers. If you need any of those
    /// packets, you will want to do the authentication manually.
    ///
    /// This function will time out after 30 seconds (theoretical absolute worst
    /// case 60 seconds.)
    pub fn connect_unauthenticated(host: &str,
                                   port: u16,
                                   username: &str)
                                   -> Result<Self> {

        let timeout = time::Instant::now();
        let mut client = Client::connect_tcp(host, port)?;
        client.set_auto_handle(true);
        client.set_hide_handled(true);
        let handshake = serverbound::Handshake::new(PROTOCOL_VERSION,
                                                    host.to_string(),
                                                    port,
                                                    2);
        let loginstart = serverbound::LoginStart::new(username.to_string());
        client.send(handshake)?;
        client.set_clientstate(ClientState::Login);
        client.send(loginstart)?;

        /* Now we wait for the PlayerAbilities packet from the server */
        'wait: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for LoginSuccess");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::PlayerAbilities(..)) => break 'wait,
                Some(ClientboundPacket::EncryptionRequest(..)) => {
                    bail!("connect_unauthenticated got EncryptionRequest");
                },
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        Ok(client)
    }

    /// Authenticate with Mojang, and then connect to the server at the
    /// given host and port. In most cases this is what you will want to use
    /// to connect to online servers.
    ///
    /// This will establish an encrypted connection to the server.
    ///
    /// Requires that you've already authenticated with Mojang, e.g. by calling
    /// yggdrasil::authenticate
    ///
    /// This will set auto_handle and hide_handled to true.
    ///
    /// This will return Ok(Client) on receival of a PlayerAbilities packet,
    /// but note that the PlayerAbilities packet and all packets received before
    /// it will not be available for consumers. If you need any of those
    /// packets, you will want to do the authentication manually.
    ///
    /// This function will time out after 30 seconds (theoretical absolute worst
    /// case 60 seconds.)
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use ozelot::{mojang, Client};
    /// let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
    ///                                      "my_password".to_string())
    ///     .perform().unwrap();
    /// let mut client = Client::connect_authenticated("minecraft.example.com",
    /// 25565,
    /// &auth).unwrap();
    /// ```
    pub fn connect_authenticated(host: &str,
                                 port: u16,
                                 auth: &AuthenticationResponse)
                                 -> Result<Self> {

        let timeout = time::Instant::now();
        let mut client = Client::connect_tcp(host, port)?;
        client.set_auto_handle(true);
        client.set_hide_handled(true);
        let handshake = serverbound::Handshake::new(PROTOCOL_VERSION,
                                                    host.to_string(),
                                                    port,
                                                    2);
        let loginstart =
            serverbound::LoginStart::new(auth.selectedProfile.name.clone());
        client.send(handshake)?;
        client.set_clientstate(ClientState::Login);
        client.send(loginstart)?;

        /* Here we wait for a LoginSuccess/EncryptionRequest packet */
        'wait: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for LoginSuccess/EncryptionRequest");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::LoginSuccess(..)) => {
                    bail!("Logged in unauthenticated")
                },
                Some(ClientboundPacket::EncryptionRequest(ref p)) => {
                    let shared_secret = utils::create_shared_secret();

                    mojang::SessionJoin::new(auth.accessToken.clone(),
                                             auth.selectedProfile.id.clone(),
                                             p.get_server_id(),
                                             &shared_secret,
                                             p.get_public_key())
                            .perform()?;

                    let encryptionresponse
                            = serverbound::EncryptionResponse::new_unencrypted(
                                &p.get_public_key(),
                                &shared_secret,
                                &p.get_verify_token())?;
                    client.send(encryptionresponse)?;
                    client.enable_encryption(&shared_secret);

                    break 'wait;
                },
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        /* Now we wait for the PlayerAbilities packet from the server */
        'wait2: loop {
            if timeout.elapsed() > time::Duration::new(30, 0) {
                bail!("Timed out waiting for PlayerAbilities packet");
            }
            client.update_inbuf()?;
            match client.read_packet()? {
                Some(ClientboundPacket::LoginDisconnect(ref p)) => {
                    bail!("Got LoginDisconnect, reason: {}", p.get_raw_chat());
                },
                Some(ClientboundPacket::PlayerAbilities(..)) => break 'wait2,
                Some(_) => (),
                None => thread::sleep(time::Duration::from_millis(10)),
            }
        }

        Ok(client)
    }

    /// Try to read some packets from the server.
    ///
    /// This function is nonblocking.
    pub fn read(&mut self) -> Result<Vec<ClientboundPacket>> {
        self.update_inbuf()?;

        let mut ret = Vec::new();
        loop {
            let packet = self.read_packet()?;
            /* push = whether to push the packet to ret */
            let mut push = match &packet {
                &Some(ClientboundPacket::LoginSuccess(_)) => false,
                &Some(ClientboundPacket::SetCompression(_)) => false,
                &Some(ClientboundPacket::KeepAlive(_)) => false,
                &Some(_) => true,
                &None => break,
            };
            if self.hide_handled == false || self.auto_handle == false {
                push = true;
            }

            if push {
                ret.push(packet
                         .expect("unreachable packet = None in client.read()"));
            }
        }

        Ok(ret)
    }

    /// Send the given packet
    ///
    /// This adds the packet to the outgoing buffer, and sends as much as is
    /// possible. Returns the length of the outgoing buffer. If this is greater
    /// than 0, you will need to call write() to send the remaining data.
    pub fn send(&mut self, packet: ServerboundPacket) -> Result<usize> {
        self.conn.send(packet)
    }

    /// Write from the outgoing buffer to the TcpStream
    ///
    /// Returns the amount of bytes written.
    pub fn write(&mut self) -> Result<usize> {
        self.conn.write()
    }

    /// Whether to automatically handle: KeepAlive, LoginSuccess and
    /// SetCompression packets. Most clients won't need to manually deal with
    /// these.
    pub fn set_auto_handle(&mut self, new: bool) {
        self.auto_handle = new;
    }

    /// Whether or not to hide packets that have been handled by ozelot from the
    /// consumer of the library.
    ///
    /// E.g. KeepAlives that are automatically handled if auto_handle = true.
    pub fn set_hide_handled(&mut self, new: bool) {
        self.hide_handled = new;
    }

    /// Attempt to close this connection, disconnecting from the server.
    ///
    /// All future sends and reads to this connection will fail.
    pub fn close(&mut self) -> Result<()> {
        self.conn.close()
    }

    /// Change the client state of this connection
    pub fn set_clientstate(&mut self, new_state: ClientState) {
        self.conn.set_clientstate(new_state)
    }

    /// Enable encryption with the given key.
    ///
    /// It is an error to enable encryption if encryption has already been
    /// enabled.
    pub fn enable_encryption(&mut self, key: &[u8; 16]) {
        self.conn.enable_encryption(key)
    }

    /// Enable compression.
    ///
    /// It is generally an error to enable compression if compression has
    /// already been enabled.
    pub fn enable_compression(&mut self, threshold: usize) {
        self.conn.enable_compression(threshold)
    }

    /// Read from the TcpStream and update the incoming buffer.
    ///
    /// This is the only way to actually read from the TcpStream. Unless you
    /// know for sure you need to call this, then you do not need to call this.
    /// I.e. if you're just using client.read(), then you do not need to call
    /// this function.
    ///
    /// This function is nonblocking.
    pub fn update_inbuf(&mut self) -> Result<()> {
        self.conn.update_inbuf()
    }

    /// Read a single packet from the internal buffer.
    ///
    /// This is only really useful if you want finegrained control over the
    /// processing of packets, or if you want to manually authenticate with
    /// the server. In most cases, you'll want to just call client.read().
    ///
    /// You MUST be sure that client.update_inbuf() has been called before this,
    /// this function will not attempt to read from the TcpStream, only from the
    /// internal buffer.
    pub fn read_packet(&mut self) -> Result<Option<ClientboundPacket>> {
        let packet = self.conn.read_packet()?;

        if self.auto_handle {
            match &packet {
                &Some(ClientboundPacket::LoginSuccess(..)) => {
                    self.set_clientstate(ClientState::Play);
                },
                &Some(ClientboundPacket::SetCompression(ref p)) => {
                    self.enable_compression(*p.get_threshold() as usize);
                },
                &Some(ClientboundPacket::KeepAlive(ref p)) => {
                    let keepalive = serverbound::KeepAlive::new(*p.get_id());
                    self.send(keepalive)?;
                },
                _ => (),
            }
        }

        Ok(packet)
    }
}
<|endoftext|>


<commit_before>use search_algorithms::board::ExtendedBoard;
use search_algorithms::board::GameResult;
use search_algorithms::alpha_beta::Score;
use search_algorithms::monte_carlo;
use pgn::PgnBoard;
use rayon::prelude::*;

pub trait TunableBoard {
    fn static_eval_with_params(&self, params: &[f32]) -> f32;
}

pub fn error<B>(positions: &mut [(B, GameResult)], params: &[f32]) -> f32
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter()
        .map(|(board, game_result)| {
            let color = board.side_to_move();
            if let Score::Val(qsearc_eval) = qsearch(&mut board.clone(), Score::Loss(0),
                                                     Score::Win(0), params) {
                let eval = qsearc_eval * color.multiplier() as f32;

                let answer = match game_result {
                    GameResult::WhiteWin => 1.0,
                    GameResult::Draw => 0.5,
                    GameResult::BlackWin => 0.0,
                };

                let error = f32::powf(answer - monte_carlo::eval_to_win_pct(eval), 2.0);
                error
            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                0.0
            }

    })
        .sum()
}

fn qsearch<B: ExtendedBoard>(board: &mut B, mut alpha: Score, beta: Score, params: &[f32]) -> Score
    where B: TunableBoard + ExtendedBoard {
    let color = board.side_to_move();

    if let Some(result) = board.game_result() {
        return Score::from_game_result(result, color)
    }

    let stand_pat = Score::Val(board.static_eval_with_params(params) * color.multiplier() as f32);

    if stand_pat >= beta {
        return beta;
    }

    alpha = alpha.max(stand_pat);

    let mut active_moves = vec![];
    board.active_moves(&mut active_moves);

    for mv in active_moves {
        let reverse_move = board.do_move(mv);

        let mut score = qsearch(board, beta, alpha, params);

        score = !score;
        board.reverse_move(reverse_move);

        if score >= beta {
            alpha = score; // TODO: Could be beta as well. Test.
            break;
        }
        if score > alpha {
            alpha = score;
        }
    }

    return alpha;

}<commit_msg>Return pv from board_tuning::qsearch()<commit_after>use search_algorithms::board::ExtendedBoard;
use search_algorithms::board::GameResult;
use search_algorithms::alpha_beta::Score;
use search_algorithms::monte_carlo;
use pgn::PgnBoard;
use rayon::prelude::*;

pub trait TunableBoard {
    fn static_eval_with_params(&self, params: &[f32]) -> f32;
}

pub fn error<B>(positions: &mut [(B, GameResult)], params: &[f32]) -> f32
    where B: TunableBoard + ExtendedBoard + PgnBoard + Send {
    positions.into_par_iter()
        .map(|(board, game_result)| {
            let color = board.side_to_move();
            if let (Score::Val(qsearc_eval), _) = qsearch(&mut board.clone(), Score::Loss(0),
                                                     Score::Win(0), params) {
                let eval = qsearc_eval * color.multiplier() as f32;

                let answer = match game_result {
                    GameResult::WhiteWin => 1.0,
                    GameResult::Draw => 0.5,
                    GameResult::BlackWin => 0.0,
                };

                let error = f32::powf(answer - monte_carlo::eval_to_win_pct(eval), 2.0);
                error
            }
            else {
                warn!("Found mate score while tuning {}.", board.to_fen());
                0.0
            }

    })
        .sum()
}

fn qsearch<B: ExtendedBoard>(board: &mut B, mut alpha: Score, beta: Score, params: &[f32])
    -> (Score, Vec<B::Move>)
    where B: TunableBoard + ExtendedBoard {
    let color = board.side_to_move();

    if let Some(result) = board.game_result() {
        return (Score::from_game_result(result, color), vec![])
    }

    let stand_pat = Score::Val(board.static_eval_with_params(params) * color.multiplier() as f32);

    if stand_pat >= beta {
        return (beta, vec![]);
    }

    alpha = alpha.max(stand_pat);
    let mut best_pv = vec![];
    let mut best_move = None;

    let mut active_moves = vec![];
    board.active_moves(&mut active_moves);

    for mv in active_moves {
        let reverse_move = board.do_move(mv.clone());

        let (mut score, mut pv) = qsearch(board, beta, alpha, params);

        score = !score;
        board.reverse_move(reverse_move);

        if score >= beta {
            return (score, vec![mv]);
        }
        if score > alpha {
            alpha = score;
            best_pv = pv;
            best_move = Some(mv);
        }
    }
    best_pv.extend(best_move);
    return (alpha, best_pv);

}<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::net::SocketAddr;

pub fn server_log_level() -> String {
    "warn".to_string()
}

pub fn server_inet() -> SocketAddr {
    "[::1]:8080".parse().unwrap()
}

pub fn control_inet() -> SocketAddr {
    "[::1]:8811".parse().unwrap()
}

pub fn control_tcp_timeout() -> u64 {
    300
}

pub fn proxy_shard_shard() -> u8 {
    0
}

pub fn proxy_shard_host() -> String { String::from("localhost") }

pub fn proxy_shard_port() -> u16 { 3000 }

pub fn cache_ttl_default() -> usize {
    600
}

pub fn cache_executor_pool() -> u16 {
    64
}

pub fn cache_disable_read() -> bool {
    false
}

pub fn cache_disable_write() -> bool {
    false
}

pub fn redis_host() -> String { String::from("localhost") }

pub fn redis_port() -> u16 { 6379 }

pub fn redis_database() -> u8 {
    0
}

pub fn redis_pool_size() -> u32 {
    80
}

pub fn redis_idle_timeout_seconds() -> u64 {
    600
}

pub fn redis_connection_timeout_seconds() -> u64 {
    1
}

pub fn redis_max_key_size() -> usize {
    256000
}

pub fn redis_max_key_expiration() -> usize {
    2592000
}
<commit_msg>Beautify<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::net::SocketAddr;

pub fn server_log_level() -> String {
    "warn".to_string()
}

pub fn server_inet() -> SocketAddr {
    "[::1]:8080".parse().unwrap()
}

pub fn control_inet() -> SocketAddr {
    "[::1]:8811".parse().unwrap()
}

pub fn control_tcp_timeout() -> u64 {
    300
}

pub fn proxy_shard_shard() -> u8 {
    0
}

pub fn proxy_shard_host() -> String {
    "localhost".to_string()
}

pub fn proxy_shard_port() -> u16 {
    3000
}

pub fn cache_ttl_default() -> usize {
    600
}

pub fn cache_executor_pool() -> u16 {
    64
}

pub fn cache_disable_read() -> bool {
    false
}

pub fn cache_disable_write() -> bool {
    false
}

pub fn redis_host() -> String {
    "localhost".to_string()
}

pub fn redis_port() -> u16 {
    6379
}

pub fn redis_database() -> u8 {
    0
}

pub fn redis_pool_size() -> u32 {
    80
}

pub fn redis_idle_timeout_seconds() -> u64 {
    600
}

pub fn redis_connection_timeout_seconds() -> u64 {
    1
}

pub fn redis_max_key_size() -> usize {
    256000
}

pub fn redis_max_key_expiration() -> usize {
    2592000
}
<|endoftext|>