<commit_before>use calx::{seeded_rng, HexFov, HexFovIter};
use calx_ecs::Entity;
use command::{Command, CommandResult};
use components;
use event::Event;
use flags::Flags;
use fov::SightFov;
use item::Slot;
use location::{Location, Portal};
use mutate::Mutate;
use query::Query;
use ron;
use spatial::{Place, Spatial};
use std::collections::HashSet;
use std::error::Error;
use std::io::{Read, Write};
use std::iter::FromIterator;
use std::slice;
use terraform::{Terraform, TerrainQuery};
use terrain::Terrain;
use volume::Volume;
use worldgen::Worldgen;
use Rng;

pub const GAME_VERSION: &str = "0.1.0";

Ecs! {
    desc: components::Desc,
    anim: components::Anim,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    stats: components::StatsComponent,
    status: components::Statuses,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Static startup game world
    worldgen: Worldgen,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
    /// Persistent random number generator.
    rng: Rng,
    /// Event queue
    events: Vec<Event>,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            worldgen: Worldgen::new(seed),
            spatial: Spatial::new(),
            flags: Flags::new(),
            rng: seeded_rng(&seed),
            events: Vec::new(),
        };

        // XXX: Clone to not run into borrow checker...
        for (loc, spawn) in ret
            .worldgen
            .spawns()
            .cloned()
            .collect::<Vec<(Location, Loadout)>>()
        {
            ret.spawn(&spawn, loc);
        }

        // TODO non-lexical borrow
        let player_entry = ret.worldgen.player_entry();
        ret.spawn_player(player_entry);

        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> Result<World, Box<Error>> {
        let ret: ron::de::Result<World> = ron::de::from_reader(reader);
        if let Ok(ref x) = ret {
            if x.version != GAME_VERSION {
                panic!(
                    "Save game version {} does not match current version {}",
                    x.version, GAME_VERSION
                );
            }
        }
        Ok(ret?)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> Result<(), Box<Error>> {
        let enc = ron::ser::to_string_pretty(self, Default::default())?;
        // TODO: Handle error from writer too...
        writeln!(writer, "{}", enc)?;
        Ok(())
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, _loc: Location) -> bool {
        //Location::origin().v2_at(loc).map_or(false, ::on_screen)
        true
    }

    fn terrain(&self, loc: Location) -> Terrain {
        let mut t = self.worldgen.get_terrain(loc);

        if t == Terrain::Door && self.has_mobs(loc) {
            // Standing in the doorway opens the door.
            t = Terrain::OpenDoor;
        }

        t
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.worldgen.get_portal(loc) }

    fn is_untouched(&self, _loc: Location) -> bool { unimplemented!() }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn get_tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.worldgen.seed() }

    fn entities(&self) -> slice::Iter<Entity> { self.ecs.iter() }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn entities_in(&self, parent: Entity) -> Vec<Entity> { self.spatial.entities_in(parent) }

    fn ecs(&self) -> &Ecs { &self.ecs }

    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity> {
        self.spatial.entity_equipped(parent, slot)
    }

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool {
        self.spatial.contains(parent, child)
    }

    fn sphere_volume(&self, origin: Location, radius: u32) -> Volume {
        Volume::sphere(self, origin, radius)
    }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        use std::mem;

        self.tick_anims();

        self.ai_main();

        self.clean_dead();
        self.flags.tick += 1;

        // Dump events.
        let mut events = Vec::new();
        mem::swap(&mut self.events, &mut events);
        Ok(events)
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot) {
        self.spatial.equip(e, parent, slot);
        self.rebuild_stats(parent);
    }

    fn set_player(&mut self, player: Option<Entity>) { self.flags.player = player; }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity {
        let e = loadout.make(&mut self.ecs);
        self.place_entity(e, loc);
        e
    }

    fn kill_entity(&mut self, e: Entity) { self.spatial.remove(e); }

    fn remove_entity(&mut self, e: Entity) { self.ecs.remove(e); }

    fn do_fov(&mut self, e: Entity) {
        if !self.ecs.map_memory.contains(e) {
            return;
        }

        if let Some(origin) = self.location(e) {
            const DEFAULT_FOV_RANGE: u32 = 7;
            const OVERLAND_FOV_RANGE: u32 = 40;

            // Long-range sight while in overworld.
            let range = if origin.z == 0 {
                OVERLAND_FOV_RANGE
            } else {
                DEFAULT_FOV_RANGE
            };

            let fov: HashSet<Location> = HashSet::from_iter(
                HexFov::new(SightFov::new(self, range, origin))
                    .add_fake_isometric_acute_corners(|pos, a| {
                        self.terrain(a.origin + pos).is_wall()
                    })
                    .map(|(pos, a)| a.origin + pos),
            );

            let memory = &mut self.ecs.map_memory[e];
            memory.seen.clear();

            for &loc in &fov {
                memory.seen.insert(loc);
                // Don't spread map memory to other sectors we haven't "properly" seen yet.
                // The edges are still shown in visual FOV for display niceness.
                if loc.sector() == origin.sector() {
                    memory.remembered.insert(loc);
                }
            }
        }
    }

    fn push_event(&mut self, event: Event) { self.events.push(event); }

    fn rng(&mut self) -> &mut Rng { &mut self.rng }

    fn ecs_mut(&mut self) -> &mut Ecs { &mut self.ecs }
}

impl Command for World {}

impl Terraform for World {
    fn set_terrain(&mut self, _loc: Location, _terrain: Terrain) {
        unimplemented!();
    }

    fn set_portal(&mut self, _loc: Location, _portal: Portal) {
        unimplemented!();
    }

    fn remove_portal(&mut self, _loc: Location) {
        unimplemented!();
    }
}
<commit_msg>Use new calx-ecs macro<commit_after>use calx::{seeded_rng, HexFov, HexFovIter};
use calx_ecs::Entity;
use command::{Command, CommandResult};
use components;
use event::Event;
use flags::Flags;
use fov::SightFov;
use item::Slot;
use location::{Location, Portal};
use mutate::Mutate;
use query::Query;
use ron;
use spatial::{Place, Spatial};
use std::collections::HashSet;
use std::error::Error;
use std::io::{Read, Write};
use std::iter::FromIterator;
use std::slice;
use terraform::{Terraform, TerrainQuery};
use terrain::Terrain;
use volume::Volume;
use worldgen::Worldgen;
use Rng;

pub const GAME_VERSION: &str = "0.1.0";

build_ecs! {
    desc: components::Desc,
    anim: components::Anim,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    stats: components::StatsComponent,
    status: components::Statuses,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Static startup game world
    worldgen: Worldgen,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
    /// Persistent random number generator.
    rng: Rng,
    /// Event queue
    events: Vec<Event>,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            worldgen: Worldgen::new(seed),
            spatial: Spatial::new(),
            flags: Flags::new(),
            rng: seeded_rng(&seed),
            events: Vec::new(),
        };

        // XXX: Clone to not run into borrow checker...
        for (loc, spawn) in ret
            .worldgen
            .spawns()
            .cloned()
            .collect::<Vec<(Location, Loadout)>>()
        {
            ret.spawn(&spawn, loc);
        }

        // TODO non-lexical borrow
        let player_entry = ret.worldgen.player_entry();
        ret.spawn_player(player_entry);

        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> Result<World, Box<Error>> {
        let ret: ron::de::Result<World> = ron::de::from_reader(reader);
        if let Ok(ref x) = ret {
            if x.version != GAME_VERSION {
                panic!(
                    "Save game version {} does not match current version {}",
                    x.version, GAME_VERSION
                );
            }
        }
        Ok(ret?)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> Result<(), Box<Error>> {
        let enc = ron::ser::to_string_pretty(self, Default::default())?;
        // TODO: Handle error from writer too...
        writeln!(writer, "{}", enc)?;
        Ok(())
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, _loc: Location) -> bool {
        //Location::origin().v2_at(loc).map_or(false, ::on_screen)
        true
    }

    fn terrain(&self, loc: Location) -> Terrain {
        let mut t = self.worldgen.get_terrain(loc);

        if t == Terrain::Door && self.has_mobs(loc) {
            // Standing in the doorway opens the door.
            t = Terrain::OpenDoor;
        }

        t
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.worldgen.get_portal(loc) }

    fn is_untouched(&self, _loc: Location) -> bool { unimplemented!() }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn get_tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.worldgen.seed() }

    fn entities(&self) -> slice::Iter<Entity> { self.ecs.iter() }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn entities_in(&self, parent: Entity) -> Vec<Entity> { self.spatial.entities_in(parent) }

    fn ecs(&self) -> &Ecs { &self.ecs }

    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity> {
        self.spatial.entity_equipped(parent, slot)
    }

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool {
        self.spatial.contains(parent, child)
    }

    fn sphere_volume(&self, origin: Location, radius: u32) -> Volume {
        Volume::sphere(self, origin, radius)
    }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        use std::mem;

        self.tick_anims();

        self.ai_main();

        self.clean_dead();
        self.flags.tick += 1;

        // Dump events.
        let mut events = Vec::new();
        mem::swap(&mut self.events, &mut events);
        Ok(events)
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot) {
        self.spatial.equip(e, parent, slot);
        self.rebuild_stats(parent);
    }

    fn set_player(&mut self, player: Option<Entity>) { self.flags.player = player; }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity {
        let e = loadout.make(&mut self.ecs);
        self.place_entity(e, loc);
        e
    }

    fn kill_entity(&mut self, e: Entity) { self.spatial.remove(e); }

    fn remove_entity(&mut self, e: Entity) { self.ecs.remove(e); }

    fn do_fov(&mut self, e: Entity) {
        if !self.ecs.map_memory.contains(e) {
            return;
        }

        if let Some(origin) = self.location(e) {
            const DEFAULT_FOV_RANGE: u32 = 7;
            const OVERLAND_FOV_RANGE: u32 = 40;

            // Long-range sight while in overworld.
            let range = if origin.z == 0 {
                OVERLAND_FOV_RANGE
            } else {
                DEFAULT_FOV_RANGE
            };

            let fov: HashSet<Location> = HashSet::from_iter(
                HexFov::new(SightFov::new(self, range, origin))
                    .add_fake_isometric_acute_corners(|pos, a| {
                        self.terrain(a.origin + pos).is_wall()
                    })
                    .map(|(pos, a)| a.origin + pos),
            );

            let memory = &mut self.ecs.map_memory[e];
            memory.seen.clear();

            for &loc in &fov {
                memory.seen.insert(loc);
                // Don't spread map memory to other sectors we haven't "properly" seen yet.
                // The edges are still shown in visual FOV for display niceness.
                if loc.sector() == origin.sector() {
                    memory.remembered.insert(loc);
                }
            }
        }
    }

    fn push_event(&mut self, event: Event) { self.events.push(event); }

    fn rng(&mut self) -> &mut Rng { &mut self.rng }

    fn ecs_mut(&mut self) -> &mut Ecs { &mut self.ecs }
}

impl Command for World {}

impl Terraform for World {
    fn set_terrain(&mut self, _loc: Location, _terrain: Terrain) {
        unimplemented!();
    }

    fn set_portal(&mut self, _loc: Location, _portal: Portal) {
        unimplemented!();
    }

    fn remove_portal(&mut self, _loc: Location) {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project 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.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::{self, Library, Face};

mod list_fonts;

use self::list_fonts::fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    keys: HashMap<::std::path::PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey, size: Size) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let scale_size = self.dpr as f64 * size.as_f32_pts() as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Ok(Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = self.get_face(desc)?;
        let key = FontKey::next();
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key, false)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            println!("got font path={:?}", path);
            Ok(self.library.new_face(path, index)?)
        }
        else {
            Err(Error::MissingFont(desc.to_owned()))
        }
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool)
                          -> Result<RasterizedGlyph, Error> {
        let faces = self.faces.clone();
        let face = faces
            .get(&glyph_key.font_key)
            .ok_or(Error::FontNotLoaded)?;

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
        let index = face.get_char_index(c as usize);

        if index == 0 && have_recursed == false {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            let new_glyph_key = GlyphKey {
                c: glyph_key.c,
                font_key: key,
                size: glyph_key.size
            };

            return self.get_rendered_glyph(&new_glyph_key, true);
        }

        face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        Ok(RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        })
    }

    fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
                    match self.keys.get(&path) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let face = self.library.new_face(path.clone(), index)?;
                            let key = FontKey::next();
                            self.faces.insert(key, face);
                            self.keys.insert(path, key);
                            Ok(key)
                        }
                    }
                }
                else {
                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))))
                }
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<commit_msg>font::fc: Remove unneeded clone<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project 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.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::{self, Library, Face};

mod list_fonts;

use self::list_fonts::fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    keys: HashMap<::std::path::PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey, size: Size) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let scale_size = self.dpr as f64 * size.as_f32_pts() as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Ok(Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = self.get_face(desc)?;
        let key = FontKey::next();
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key, false)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            println!("got font path={:?}", path);
            Ok(self.library.new_face(path, index)?)
        }
        else {
            Err(Error::MissingFont(desc.to_owned()))
        }
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool)
                          -> Result<RasterizedGlyph, Error> {
        let faces = self.faces.clone();
        let face = faces
            .get(&glyph_key.font_key)
            .ok_or(Error::FontNotLoaded)?;

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
        let index = face.get_char_index(c as usize);

        if index == 0 && have_recursed == false {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            let new_glyph_key = GlyphKey {
                c: glyph_key.c,
                font_key: key,
                size: glyph_key.size
            };

            return self.get_rendered_glyph(&new_glyph_key, true);
        }

        face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        Ok(RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        })
    }

    fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
                    match self.keys.get(&path) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let face = self.library.new_face(&path, index)?;
                            let key = FontKey::next();
                            self.faces.insert(key, face);
                            self.keys.insert(path, key);
                            Ok(key)
                        }
                    }
                }
                else {
                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))))
                }
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::mem::transmute;

pub static VGA_START: *mut u16 = 0xb8000 as *mut u16; // TODO(ryan) this shouldn't be exposed
pub static VGA_MAX: (uint, uint) = (80, 24);

pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

pub struct VGA { // TODO(ryan) struct fields shouldn't be exposed
  pub mapped: *mut u16,
  pub max: (uint, uint)
}

impl VGA {

  #[inline(always)]
  pub fn new() -> VGA {
    VGA { mapped: VGA_START, max: VGA_MAX }
  }

  pub fn put(&mut self, point: (uint, uint), chr: u8, fg: Color, bg: Color) -> bool {
      let (desired_x, desired_y) = point;
      let (my_x, my_y) = self.max;
      if desired_x >= my_x || desired_y >= my_y {
	false
      } else {
	unsafe {
	  let as_mut: *mut u16 = transmute(self.mapped.offset((my_x * desired_y + desired_x) as int));
	  *as_mut = make_vgaentry(chr, make_color(fg, bg));
	}
	true
      }
  }

  pub fn get(&mut self, point: (uint, uint)) -> Option<(u8, Color, Color)> {
    let (desired_x, desired_y) = point;
      let (my_x, my_y) = self.max;
      if desired_x >= my_x || desired_y >= my_y {
	None
      } else {
	unsafe {
	  let entry = self.mapped.offset((my_x * desired_y + desired_x) as int);
	  Some(get_vgaentry(*entry))
	}
      }
  }

  pub fn x_max(&self) -> uint {
    let (x, _) = self.max;
    x as uint
  }

  pub fn y_max(&self) -> uint {
    let (_, y) = self.max;
    y as uint
  }

}

fn make_color(fg: Color, bg: Color) -> u8 {
  (fg as u8) | (bg as u8) << 4
}

fn get_vgaentry(entry: u16) -> (u8, Color, Color) {
  unsafe {
    let (c, color): (u8, u8) = transmute(entry);
    (c, transmute(color & 0xf), transmute(color >> 4))
  }
}

fn make_vgaentry(c: u8, color_entry: u8) -> u16 {
  let c8: u8 = c as u8;
  let c16: u16 = c8 as u16;
  let color16: u16 = color_entry as u16;
  c16 | color16 << 8
}
<commit_msg>pub -> priv fixing some todos<commit_after>use core::prelude::*;
use core::mem::transmute;

static VGA_START: *mut u16 = 0xb8000 as *mut u16;
static VGA_MAX: (uint, uint) = (80, 24);

pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

pub struct VGA {
  mapped: *mut u16,
  max:    (uint, uint)
}

impl VGA {

  #[inline(always)]
  pub fn new() -> VGA {
    VGA { mapped: VGA_START, max: VGA_MAX }
  }

  pub fn put(&mut self, point: (uint, uint), chr: u8, fg: Color, bg: Color) -> bool {
      let (desired_x, desired_y) = point;
      let (my_x, my_y) = self.max;
      if desired_x >= my_x || desired_y >= my_y {
	false
      } else {
	unsafe {
	  let as_mut: *mut u16 = transmute(self.mapped.offset((my_x * desired_y + desired_x) as int));
	  *as_mut = make_vgaentry(chr, make_color(fg, bg));
	}
	true
      }
  }

  pub fn get(&mut self, point: (uint, uint)) -> Option<(u8, Color, Color)> {
    let (desired_x, desired_y) = point;
      let (my_x, my_y) = self.max;
      if desired_x >= my_x || desired_y >= my_y {
	None
      } else {
	unsafe {
	  let entry = self.mapped.offset((my_x * desired_y + desired_x) as int);
	  Some(get_vgaentry(*entry))
	}
      }
  }

  pub fn x_max(&self) -> uint {
    let (x, _) = self.max;
    x as uint
  }

  pub fn y_max(&self) -> uint {
    let (_, y) = self.max;
    y as uint
  }

}

fn make_color(fg: Color, bg: Color) -> u8 {
  (fg as u8) | (bg as u8) << 4
}

fn get_vgaentry(entry: u16) -> (u8, Color, Color) {
  unsafe {
    let (c, color): (u8, u8) = transmute(entry);
    (c, transmute(color & 0xf), transmute(color >> 4))
  }
}

fn make_vgaentry(c: u8, color_entry: u8) -> u16 {
  let c8: u8 = c as u8;
  let c16: u16 = c8 as u16;
  let color16: u16 = color_entry as u16;
  c16 | color16 << 8
}
<|endoftext|>


<commit_before>use tree_sitter::{Point, Range, Tree};

#[derive(Debug)]
pub struct ScopeSequence(Vec<ScopeStack>);

type ScopeStack = Vec<&'static str>;

impl ScopeSequence {
    pub fn new(tree: &Tree) -> Self {
        let mut result = ScopeSequence(Vec::new());
        let mut scope_stack = Vec::new();

        let mut cursor = tree.walk();
        let mut visited_children = false;
        loop {
            let node = cursor.node();
            for _ in result.0.len()..node.start_byte() {
                result.0.push(scope_stack.clone());
            }
            if visited_children {
                for _ in result.0.len()..node.end_byte() {
                    result.0.push(scope_stack.clone());
                }
                scope_stack.pop();
                if cursor.goto_next_sibling() {
                    visited_children = false;
                } else if !cursor.goto_parent() {
                    break;
                }
            } else {
                scope_stack.push(cursor.node().kind());
                if !cursor.goto_first_child() {
                    visited_children = true;
                }
            }
        }

        result
    }

    pub fn check_changes(
        &self,
        other: &ScopeSequence,
        text: &Vec<u8>,
        known_changed_ranges: &Vec<Range>,
    ) -> Result<(), String> {
        if self.0.len() != text.len() {
            panic!(
                "Inconsistent scope sequence: {:?}",
                self.0
                    .iter()
                    .zip(text.iter().map(|c| *c as char))
                    .collect::<Vec<_>>()
            );
        }

        assert_eq!(self.0.len(), other.0.len());
        let mut position = Point { row: 0, column: 0 };
        for (i, stack) in self.0.iter().enumerate() {
            let other_stack = &other.0[i];
            if *stack != *other_stack {
                let containing_range = known_changed_ranges
                    .iter()
                    .find(|range| range.start_point <= position && position < range.end_point);
                if containing_range.is_none() {
                    let line = &text[(i - position.column)..]
                        .split(|c| *c == '\n' as u8)
                        .next()
                        .unwrap();
                    return Err(format!(
                        concat!(
                            "Position: {}\n",
                            "Byte offset: {}\n",
                            "Line: {}\n",
                            "{}^\n",
                            "Old scopes: {:?}\n",
                            "New scopes: {:?}\n",
                            "Invalidated ranges: {:?}",
                        ),
                        position,
                        i,
                        String::from_utf8_lossy(line),
                        String::from(" ").repeat(position.column + "Line: ".len()),
                        stack,
                        other_stack,
                        known_changed_ranges,
                    ));
                }
            }

            if text[i] == '\n' as u8 {
                position.row += 1;
                position.column = 0;
            } else {
                position.column += 1;
            }
        }
        Ok(())
    }
}
<commit_msg>Loosen randomized changed range assertions on newline characters<commit_after>use tree_sitter::{Point, Range, Tree};

#[derive(Debug)]
pub struct ScopeSequence(Vec<ScopeStack>);

type ScopeStack = Vec<&'static str>;

impl ScopeSequence {
    pub fn new(tree: &Tree) -> Self {
        let mut result = ScopeSequence(Vec::new());
        let mut scope_stack = Vec::new();

        let mut cursor = tree.walk();
        let mut visited_children = false;
        loop {
            let node = cursor.node();
            for _ in result.0.len()..node.start_byte() {
                result.0.push(scope_stack.clone());
            }
            if visited_children {
                for _ in result.0.len()..node.end_byte() {
                    result.0.push(scope_stack.clone());
                }
                scope_stack.pop();
                if cursor.goto_next_sibling() {
                    visited_children = false;
                } else if !cursor.goto_parent() {
                    break;
                }
            } else {
                scope_stack.push(cursor.node().kind());
                if !cursor.goto_first_child() {
                    visited_children = true;
                }
            }
        }

        result
    }

    pub fn check_changes(
        &self,
        other: &ScopeSequence,
        text: &Vec<u8>,
        known_changed_ranges: &Vec<Range>,
    ) -> Result<(), String> {
        if self.0.len() != text.len() {
            panic!(
                "Inconsistent scope sequence: {:?}",
                self.0
                    .iter()
                    .zip(text.iter().map(|c| *c as char))
                    .collect::<Vec<_>>()
            );
        }

        assert_eq!(self.0.len(), other.0.len());
        let mut position = Point { row: 0, column: 0 };
        for (i, stack) in self.0.iter().enumerate() {
            let other_stack = &other.0[i];
            if *stack != *other_stack && ![b'\r', b'\n'].contains(&text[i]) {
                let containing_range = known_changed_ranges
                    .iter()
                    .find(|range| range.start_point <= position && position < range.end_point);
                if containing_range.is_none() {
                    let line = &text[(i - position.column)..]
                        .split(|c| *c == '\n' as u8)
                        .next()
                        .unwrap();
                    return Err(format!(
                        concat!(
                            "Position: {}\n",
                            "Byte offset: {}\n",
                            "Line: {}\n",
                            "{}^\n",
                            "Old scopes: {:?}\n",
                            "New scopes: {:?}\n",
                            "Invalidated ranges: {:?}",
                        ),
                        position,
                        i,
                        String::from_utf8_lossy(line),
                        String::from(" ").repeat(position.column + "Line: ".len()),
                        stack,
                        other_stack,
                        known_changed_ranges,
                    ));
                }
            }

            if text[i] == '\n' as u8 {
                position.row += 1;
                position.column = 0;
            } else {
                position.column += 1;
            }
        }
        Ok(())
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::connector::{create_tls_config, ALPN_H1};
use crate::cookie::Cookie;
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
use crate::hosts::replace_host;
use crate::http_loader::HttpState;
use embedder_traits::resources::{self, Resource};
use headers::Host;
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use http::uri::Authority;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::request::{RequestBuilder, RequestMode};
use net_traits::{CookieSource, MessageData};
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
use openssl::ssl::SslStream;
use servo_url::ServoUrl;
use std::fs;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use url::Url;
use ws::util::TcpStream;
use ws::{
    CloseCode, Factory, Handler, Handshake, Message, Request, Response as WsResponse, Sender,
    WebSocket,
};
use ws::{Error as WebSocketError, ErrorKind as WebSocketErrorKind, Result as WebSocketResult};

/// A client for connecting to a websocket server
#[derive(Clone)]
struct Client<'a> {
    origin: &'a str,
    host: &'a Host,
    protocols: &'a [String],
    http_state: &'a Arc<HttpState>,
    resource_url: &'a ServoUrl,
    event_sender: &'a IpcSender<WebSocketNetworkEvent>,
    protocol_in_use: Option<String>,
    certificate_path: Option<String>,
}

impl<'a> Factory for Client<'a> {
    type Handler = Self;

    fn connection_made(&mut self, _: Sender) -> Self::Handler {
        self.clone()
    }

    fn connection_lost(&mut self, _: Self::Handler) {
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }
}

impl<'a> Handler for Client<'a> {
    fn build_request(&mut self, url: &Url) -> WebSocketResult<Request> {
        let mut req = Request::from_url(url)?;
        req.headers_mut()
            .push(("Origin".to_string(), self.origin.as_bytes().to_owned()));
        req.headers_mut().push((
            "Host".to_string(),
            format!("{}", self.host).as_bytes().to_owned(),
        ));

        for protocol in self.protocols {
            req.add_protocol(protocol);
        }

        let mut cookie_jar = self.http_state.cookie_jar.write().unwrap();
        cookie_jar.remove_expired_cookies_for_url(self.resource_url);
        if let Some(cookie_list) = cookie_jar.cookies_for_url(self.resource_url, CookieSource::HTTP)
        {
            req.headers_mut()
                .push(("Cookie".into(), cookie_list.as_bytes().to_owned()))
        }

        Ok(req)
    }

    fn on_open(&mut self, shake: Handshake) -> WebSocketResult<()> {
        let mut headers = HeaderMap::new();
        for &(ref name, ref value) in shake.response.headers().iter() {
            let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
            let value = HeaderValue::from_bytes(&value).unwrap();

            headers.insert(name, value);
        }

        let mut jar = self.http_state.cookie_jar.write().unwrap();
        // TODO(eijebong): Replace thise once typed headers settled on a cookie impl
        for cookie in headers.get_all(header::SET_COOKIE) {
            if let Ok(s) = std::str::from_utf8(cookie.as_bytes()) {
                if let Some(cookie) =
                    Cookie::from_cookie_string(s.into(), self.resource_url, CookieSource::HTTP)
                {
                    jar.push(cookie, self.resource_url, CookieSource::HTTP);
                }
            }
        }

        self.http_state
            .hsts_list
            .write()
            .unwrap()
            .update_hsts_list_from_response(self.resource_url, &headers);

        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::ConnectionEstablished {
                protocol_in_use: self.protocol_in_use.clone(),
            });
        Ok(())
    }

    fn on_message(&mut self, message: Message) -> WebSocketResult<()> {
        let message = match message {
            Message::Text(message) => MessageData::Text(message),
            Message::Binary(message) => MessageData::Binary(message),
        };
        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::MessageReceived(message));

        Ok(())
    }

    fn on_error(&mut self, err: WebSocketError) {
        debug!("Error in WebSocket communication: {:?}", err);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }

    fn on_response(&mut self, res: &WsResponse) -> WebSocketResult<()> {
        let protocol_in_use = res.protocol()?;

        if let Some(protocol_name) = protocol_in_use {
            if !self.protocols.is_empty() && !self.protocols.iter().any(|p| protocol_name == (*p)) {
                let error = WebSocketError::new(
                    WebSocketErrorKind::Protocol,
                    "Protocol in Use not in client-supplied protocol list",
                );
                return Err(error);
            }
            self.protocol_in_use = Some(protocol_name.into());
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Close(
            Some(code.into()),
            reason.to_owned(),
        ));
    }

    fn upgrade_ssl_client(
        &mut self,
        stream: TcpStream,
        url: &Url,
    ) -> WebSocketResult<SslStream<TcpStream>> {
        let certs = match self.certificate_path {
            Some(ref path) => fs::read_to_string(path).expect("Couldn't not find certificate file"),
            None => resources::read_string(Resource::SSLCertificates),
        };

        let domain = self
            .resource_url
            .as_url()
            .domain()
            .ok_or(WebSocketError::new(
                WebSocketErrorKind::Protocol,
                format!("Unable to parse domain from {}. Needed for SSL.", url),
            ))?;
        let tls_config = create_tls_config(&certs, ALPN_H1);
        tls_config
            .build()
            .connect(domain, stream)
            .map_err(WebSocketError::from)
    }
}

pub fn init(
    req_builder: RequestBuilder,
    resource_event_sender: IpcSender<WebSocketNetworkEvent>,
    dom_action_receiver: IpcReceiver<WebSocketDomAction>,
    http_state: Arc<HttpState>,
    certificate_path: Option<String>,
) {
    thread::Builder::new()
        .name(format!("WebSocket connection to {}", req_builder.url))
        .spawn(move || {
            let mut req_builder = req_builder;
            let protocols = match req_builder.mode {
                RequestMode::WebSocket { protocols } => protocols,
                _ => panic!(
                    "Received a RequestBuilder with a non-websocket mode in websocket_loader"
                ),
            };

            // https://fetch.spec.whatwg.org/#websocket-opening-handshake
            // By standard, we should work with an http(s):// URL (req_url),
            // but as ws-rs expects to be called with a ws(s):// URL (net_url)
            // we upgrade ws to wss, so we don't have to convert http(s) back to ws(s).
            http_state
                .hsts_list
                .read()
                .unwrap()
                .apply_hsts_rules(&mut req_builder.url);

            let scheme = req_builder.url.scheme();
            let mut req_url = req_builder.url.clone();
            if scheme == "ws" {
                req_url.as_mut_url().set_scheme("http").unwrap();
            } else if scheme == "wss" {
                req_url.as_mut_url().set_scheme("https").unwrap();
            }

            if should_be_blocked_due_to_bad_port(&req_url) {
                debug!("Failed to establish a WebSocket connection: port blocked");
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

            let host = replace_host(req_builder.url.host_str().unwrap());
            let mut net_url = req_builder.url.clone().into_url();
            net_url.set_host(Some(&host)).unwrap();

            let host = Host::from(
                format!(
                    "{}{}",
                    req_builder.url.host_str().unwrap(),
                    req_builder
                        .url
                        .port_or_known_default()
                        .map(|v| format!(":{}", v))
                        .unwrap_or("".into())
                )
                .parse::<Authority>()
                .unwrap(),
            );

            let client = Client {
                origin: &req_builder.origin.ascii_serialization(),
                host: &host,
                protocols: &protocols,
                http_state: &http_state,
                resource_url: &req_builder.url,
                event_sender: &resource_event_sender,
                protocol_in_use: None,
                certificate_path,
            };
            let mut ws = WebSocket::new(client).unwrap();

            if let Err(e) = ws.connect(net_url) {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                return;
            };

            let ws_sender = ws.broadcaster();
            let initiated_close = Arc::new(AtomicBool::new(false));

            ROUTER.add_route(
                dom_action_receiver.to_opaque(),
                Box::new(move |message| {
                    let dom_action = message.to().expect("Ws dom_action message to deserialize");
                    match dom_action {
                        WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                            if let Err(e) = ws_sender.send(Message::text(data)) {
                                warn!("Error sending websocket message: {:?}", e);
                            }
                        },
                        WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                            if let Err(e) = ws_sender.send(Message::binary(data)) {
                                warn!("Error sending websocket message: {:?}", e);
                            }
                        },
                        WebSocketDomAction::Close(code, reason) => {
                            if !initiated_close.fetch_or(true, Ordering::SeqCst) {
                                match code {
                                    Some(code) => {
                                        if let Err(e) = ws_sender.close_with_reason(
                                            code.into(),
                                            reason.unwrap_or("".to_owned()),
                                        ) {
                                            warn!("Error closing websocket: {:?}", e);
                                        }
                                    },
                                    None => {
                                        if let Err(e) = ws_sender.close(CloseCode::Status) {
                                            warn!("Error closing websocket: {:?}", e);
                                        }
                                    },
                                };
                            }
                        },
                    }
                }),
            );

            if let Err(e) = ws.run() {
                debug!("Failed to run WebSocket: {:?}", e);
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
            };
        })
        .expect("Thread spawning failed");
}
<commit_msg>Remove duplicate Host header from initial websocket request.<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 https://mozilla.org/MPL/2.0/. */

use crate::connector::{create_tls_config, ALPN_H1};
use crate::cookie::Cookie;
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
use crate::hosts::replace_host;
use crate::http_loader::HttpState;
use embedder_traits::resources::{self, Resource};
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::request::{RequestBuilder, RequestMode};
use net_traits::{CookieSource, MessageData};
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
use openssl::ssl::SslStream;
use servo_url::ServoUrl;
use std::fs;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use url::Url;
use ws::util::TcpStream;
use ws::{
    CloseCode, Factory, Handler, Handshake, Message, Request, Response as WsResponse, Sender,
    WebSocket,
};
use ws::{Error as WebSocketError, ErrorKind as WebSocketErrorKind, Result as WebSocketResult};

/// A client for connecting to a websocket server
#[derive(Clone)]
struct Client<'a> {
    origin: &'a str,
    protocols: &'a [String],
    http_state: &'a Arc<HttpState>,
    resource_url: &'a ServoUrl,
    event_sender: &'a IpcSender<WebSocketNetworkEvent>,
    protocol_in_use: Option<String>,
    certificate_path: Option<String>,
}

impl<'a> Factory for Client<'a> {
    type Handler = Self;

    fn connection_made(&mut self, _: Sender) -> Self::Handler {
        self.clone()
    }

    fn connection_lost(&mut self, _: Self::Handler) {
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }
}

impl<'a> Handler for Client<'a> {
    fn build_request(&mut self, url: &Url) -> WebSocketResult<Request> {
        let mut req = Request::from_url(url)?;
        req.headers_mut()
            .push(("Origin".to_string(), self.origin.as_bytes().to_owned()));

        for protocol in self.protocols {
            req.add_protocol(protocol);
        }

        let mut cookie_jar = self.http_state.cookie_jar.write().unwrap();
        cookie_jar.remove_expired_cookies_for_url(self.resource_url);
        if let Some(cookie_list) = cookie_jar.cookies_for_url(self.resource_url, CookieSource::HTTP)
        {
            req.headers_mut()
                .push(("Cookie".into(), cookie_list.as_bytes().to_owned()))
        }

        Ok(req)
    }

    fn on_open(&mut self, shake: Handshake) -> WebSocketResult<()> {
        let mut headers = HeaderMap::new();
        for &(ref name, ref value) in shake.response.headers().iter() {
            let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
            let value = HeaderValue::from_bytes(&value).unwrap();

            headers.insert(name, value);
        }

        let mut jar = self.http_state.cookie_jar.write().unwrap();
        // TODO(eijebong): Replace thise once typed headers settled on a cookie impl
        for cookie in headers.get_all(header::SET_COOKIE) {
            if let Ok(s) = std::str::from_utf8(cookie.as_bytes()) {
                if let Some(cookie) =
                    Cookie::from_cookie_string(s.into(), self.resource_url, CookieSource::HTTP)
                {
                    jar.push(cookie, self.resource_url, CookieSource::HTTP);
                }
            }
        }

        self.http_state
            .hsts_list
            .write()
            .unwrap()
            .update_hsts_list_from_response(self.resource_url, &headers);

        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::ConnectionEstablished {
                protocol_in_use: self.protocol_in_use.clone(),
            });
        Ok(())
    }

    fn on_message(&mut self, message: Message) -> WebSocketResult<()> {
        let message = match message {
            Message::Text(message) => MessageData::Text(message),
            Message::Binary(message) => MessageData::Binary(message),
        };
        let _ = self
            .event_sender
            .send(WebSocketNetworkEvent::MessageReceived(message));

        Ok(())
    }

    fn on_error(&mut self, err: WebSocketError) {
        debug!("Error in WebSocket communication: {:?}", err);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Fail);
    }

    fn on_response(&mut self, res: &WsResponse) -> WebSocketResult<()> {
        let protocol_in_use = res.protocol()?;

        if let Some(protocol_name) = protocol_in_use {
            if !self.protocols.is_empty() && !self.protocols.iter().any(|p| protocol_name == (*p)) {
                let error = WebSocketError::new(
                    WebSocketErrorKind::Protocol,
                    "Protocol in Use not in client-supplied protocol list",
                );
                return Err(error);
            }
            self.protocol_in_use = Some(protocol_name.into());
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
        let _ = self.event_sender.send(WebSocketNetworkEvent::Close(
            Some(code.into()),
            reason.to_owned(),
        ));
    }

    fn upgrade_ssl_client(
        &mut self,
        stream: TcpStream,
        url: &Url,
    ) -> WebSocketResult<SslStream<TcpStream>> {
        let certs = match self.certificate_path {
            Some(ref path) => fs::read_to_string(path).expect("Couldn't not find certificate file"),
            None => resources::read_string(Resource::SSLCertificates),
        };

        let domain = self
            .resource_url
            .as_url()
            .domain()
            .ok_or(WebSocketError::new(
                WebSocketErrorKind::Protocol,
                format!("Unable to parse domain from {}. Needed for SSL.", url),
            ))?;
        let tls_config = create_tls_config(&certs, ALPN_H1);
        tls_config
            .build()
            .connect(domain, stream)
            .map_err(WebSocketError::from)
    }
}

pub fn init(
    req_builder: RequestBuilder,
    resource_event_sender: IpcSender<WebSocketNetworkEvent>,
    dom_action_receiver: IpcReceiver<WebSocketDomAction>,
    http_state: Arc<HttpState>,
    certificate_path: Option<String>,
) {
    thread::Builder::new()
        .name(format!("WebSocket connection to {}", req_builder.url))
        .spawn(move || {
            let mut req_builder = req_builder;
            let protocols = match req_builder.mode {
                RequestMode::WebSocket { protocols } => protocols,
                _ => panic!(
                    "Received a RequestBuilder with a non-websocket mode in websocket_loader"
                ),
            };

            // https://fetch.spec.whatwg.org/#websocket-opening-handshake
            // By standard, we should work with an http(s):// URL (req_url),
            // but as ws-rs expects to be called with a ws(s):// URL (net_url)
            // we upgrade ws to wss, so we don't have to convert http(s) back to ws(s).
            http_state
                .hsts_list
                .read()
                .unwrap()
                .apply_hsts_rules(&mut req_builder.url);

            let scheme = req_builder.url.scheme();
            let mut req_url = req_builder.url.clone();
            if scheme == "ws" {
                req_url.as_mut_url().set_scheme("http").unwrap();
            } else if scheme == "wss" {
                req_url.as_mut_url().set_scheme("https").unwrap();
            }

            if should_be_blocked_due_to_bad_port(&req_url) {
                debug!("Failed to establish a WebSocket connection: port blocked");
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
                return;
            }

            let host = replace_host(req_builder.url.host_str().unwrap());
            let mut net_url = req_builder.url.clone().into_url();
            net_url.set_host(Some(&host)).unwrap();

            let client = Client {
                origin: &req_builder.origin.ascii_serialization(),
                protocols: &protocols,
                http_state: &http_state,
                resource_url: &req_builder.url,
                event_sender: &resource_event_sender,
                protocol_in_use: None,
                certificate_path,
            };
            let mut ws = WebSocket::new(client).unwrap();

            if let Err(e) = ws.connect(net_url) {
                debug!("Failed to establish a WebSocket connection: {:?}", e);
                return;
            };

            let ws_sender = ws.broadcaster();
            let initiated_close = Arc::new(AtomicBool::new(false));

            ROUTER.add_route(
                dom_action_receiver.to_opaque(),
                Box::new(move |message| {
                    let dom_action = message.to().expect("Ws dom_action message to deserialize");
                    match dom_action {
                        WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                            if let Err(e) = ws_sender.send(Message::text(data)) {
                                warn!("Error sending websocket message: {:?}", e);
                            }
                        },
                        WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                            if let Err(e) = ws_sender.send(Message::binary(data)) {
                                warn!("Error sending websocket message: {:?}", e);
                            }
                        },
                        WebSocketDomAction::Close(code, reason) => {
                            if !initiated_close.fetch_or(true, Ordering::SeqCst) {
                                match code {
                                    Some(code) => {
                                        if let Err(e) = ws_sender.close_with_reason(
                                            code.into(),
                                            reason.unwrap_or("".to_owned()),
                                        ) {
                                            warn!("Error closing websocket: {:?}", e);
                                        }
                                    },
                                    None => {
                                        if let Err(e) = ws_sender.close(CloseCode::Status) {
                                            warn!("Error closing websocket: {:?}", e);
                                        }
                                    },
                                };
                            }
                        },
                    }
                }),
            );

            if let Err(e) = ws.run() {
                debug!("Failed to run WebSocket: {:?}", e);
                let _ = resource_event_sender.send(WebSocketNetworkEvent::Fail);
            };
        })
        .expect("Thread spawning failed");
}
<|endoftext|>


<commit_before>// helper for transmutation, shown below.
type RustClosure = (int,int);

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

struct Handler<T, U:Copy> {
    handle: RustClosure
}

struct ProtectBlock<T, U:Copy> {
    cond: &Condition<T, U>,
    inner: RustClosure
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    prev: Option<@Handler<T, U>>,
    drop {
        match self.prev {
            None => (),
            Some(p) =>
            unsafe {
                debug!("Guard: popping handler from TLS");
                task::local_data::local_data_set(self.cond.key, p)
            }
        }
    }
}

struct HandleBlock<T, U:Copy> {
    pb: &ProtectBlock<T,U>,
    prev: Option<@Handler<T,U>>,
    handler: @Handler<T,U>,
    drop {
        unsafe {
            debug!("HandleBlock: pushing handler to TLS");
            let _g = Guard { cond: self.pb.cond,
                             prev: self.prev };
            task::local_data::local_data_set(self.pb.cond.key,
                                             self.handler);
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            let f : &fn() = ::cast::transmute(self.pb.inner);
            debug!("HandleBlock: invoking protected code");
            f();
            debug!("HandleBlock: returned from protected code");
        }
    }
}

impl<T, U: Copy> ProtectBlock<T,U> {
    fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
        unsafe {
            debug!("ProtectBlock.handle: setting up handler block");
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.cond.key);
            HandleBlock { pb: self,
                          prev: prev,
                          handler: @Handler{handle: *p} }
        }
    }
}

impl<T, U: Copy>  Condition<T,U> {

    fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self<T,U> {
        unsafe {
            let prev = task::local_data::local_data_get(self.key);
            let g = Guard { cond: self, prev: prev };
            debug!("Guard: pushing handler to TLS");
            let p : *RustClosure = ::cast::transmute(&h);
            let h = @Handler{handle: *p};
            task::local_data::local_data_set(self.key, h);
            move g
        }
    }

    fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
        unsafe {
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            debug!("Condition.protect: setting up protected block");
            let p : *RustClosure = ::cast::transmute(&inner);
            ProtectBlock { cond: self,
                           inner: *p }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_get(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
                    f(t)
                }
            }
        }
    }
}

#[cfg(test)]
fn sadness_key(_x: @Handler<int,int>) { }

#[cfg(test)]
fn trouble(i: int) {
    // Condition should work as a const, just limitations in consts.
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };
    debug!("trouble: raising conition");
    let j = sadness_condition.raise(&i);
    debug!("trouble: handler recovered with %d", j);
}

#[test]
fn test1() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut i = 10;

    let b = do sadness_condition.protect {
        debug!("test1: in protected block");
        trouble(1);
        trouble(2);
        trouble(3);
    };

    do b.handle |j| {
        debug!("test1: in handler");
        i += *j;
        i
    };

    assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_inner: in protected block");
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_inner: in handler");
        inner_trapped = true;
        0
    };

    assert inner_trapped;
}

#[test]
fn nested_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_outer: in protected block");
        nested_test_inner();
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_outer: in handler");
        outer_trapped = true;
        0
    };

    assert outer_trapped;
}

#[cfg(test)]
fn nested_guard_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_inner: in handler");
        inner_trapped = true;
        0
    };

    debug!("nested_guard_test_inner: in protected block");
    trouble(1);

    assert inner_trapped;
}

#[test]
fn nested_guard_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_outer: in handler");
        outer_trapped = true;
        0
    };

    debug!("nested_guard_test_outer: in protected block");
    nested_guard_test_inner();
    trouble(1);

    assert outer_trapped;
}
<commit_msg>core: add 3rd proposed interface (trap/in) to conditions.<commit_after>// helper for transmutation, shown below.
type RustClosure = (int,int);

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

struct Handler<T, U:Copy> {
    handle: RustClosure
}

struct ProtectBlock<T, U:Copy> {
    cond: &Condition<T, U>,
    inner: RustClosure
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    prev: Option<@Handler<T, U>>,
    drop {
        match self.prev {
            None => (),
            Some(p) =>
            unsafe {
                debug!("Guard: popping handler from TLS");
                task::local_data::local_data_set(self.cond.key, p)
            }
        }
    }
}

struct HandleBlock<T, U:Copy> {
    pb: &ProtectBlock<T,U>,
    prev: Option<@Handler<T,U>>,
    handler: @Handler<T,U>,
    drop {
        unsafe {
            debug!("HandleBlock: pushing handler to TLS");
            let _g = Guard { cond: self.pb.cond,
                             prev: self.prev };
            task::local_data::local_data_set(self.pb.cond.key,
                                             self.handler);
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            let f : &fn() = ::cast::transmute(self.pb.inner);
            debug!("HandleBlock: invoking protected code");
            f();
            debug!("HandleBlock: returned from protected code");
        }
    }
}

struct Trap<T, U:Copy> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U: Copy> ProtectBlock<T,U> {
    fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
        unsafe {
            debug!("ProtectBlock.handle: setting up handler block");
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.cond.key);
            HandleBlock { pb: self,
                          prev: prev,
                          handler: @Handler{handle: *p} }
        }
    }
}

impl<T, U: Copy> Trap<T,U> {
    fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let prev = task::local_data::local_data_get(self.cond.key);
            let _g = Guard { cond: self.cond,
                             prev: prev };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

impl<T, U: Copy>  Condition<T,U> {

    fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self<T,U> {
        unsafe {
            let prev = task::local_data::local_data_get(self.key);
            let g = Guard { cond: self, prev: prev };
            debug!("Guard: pushing handler to TLS");
            let p : *RustClosure = ::cast::transmute(&h);
            let h = @Handler{handle: *p};
            task::local_data::local_data_set(self.key, h);
            move g
        }
    }

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let h = @Handler{handle: *p};
            move Trap { cond: self, handler: h }
        }
    }

    fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
        unsafe {
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            debug!("Condition.protect: setting up protected block");
            let p : *RustClosure = ::cast::transmute(&inner);
            ProtectBlock { cond: self,
                           inner: *p }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_get(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
                    f(t)
                }
            }
        }
    }
}

#[cfg(test)]
fn sadness_key(_x: @Handler<int,int>) { }

#[cfg(test)]
fn trouble(i: int) {
    // Condition should work as a const, just limitations in consts.
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };
    debug!("trouble: raising conition");
    let j = sadness_condition.raise(&i);
    debug!("trouble: handler recovered with %d", j);
}

#[test]
fn test1() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut i = 10;

    let b = do sadness_condition.protect {
        debug!("test1: in protected block");
        trouble(1);
        trouble(2);
        trouble(3);
    };

    do b.handle |j| {
        debug!("test1: in handler");
        i += *j;
        i
    };

    assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_inner: in protected block");
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_inner: in handler");
        inner_trapped = true;
        0
    };

    assert inner_trapped;
}

#[test]
fn nested_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_outer: in protected block");
        nested_test_inner();
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_outer: in handler");
        outer_trapped = true;
        0
    };

    assert outer_trapped;
}

#[cfg(test)]
fn nested_guard_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_inner: in handler");
        inner_trapped = true;
        0
    };

    debug!("nested_guard_test_inner: in protected block");
    trouble(1);

    assert inner_trapped;
}

#[test]
fn nested_guard_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_outer: in handler");
        outer_trapped = true;
        0
    };

    debug!("nested_guard_test_outer: in protected block");
    nested_guard_test_inner();
    trouble(1);

    assert outer_trapped;
}

#[cfg(test)]
fn nested_trap_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    do sadness_condition.trap(|_j| {
        debug!("nested_trap_test_inner: in handler");
        inner_trapped = true;
        0
    }).in {
        debug!("nested_trap_test_inner: in protected block");
        trouble(1);
    }

    assert inner_trapped;
}

#[test]
fn nested_trap_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    do sadness_condition.trap(|_j| {
        debug!("nested_trap_test_outer: in handler");
        outer_trapped = true; 0
    }).in {
        debug!("nested_guard_test_outer: in protected block");
        nested_trap_test_inner();
        trouble(1);
    }

    assert outer_trapped;
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use task;

// helper for transmutation, shown below.
type RustClosure = (int,int);
pub struct Handler<T, U> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>,
}

pub struct Condition<T, U> {
    name: &static/str,
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

impl<T, U>  Condition<T,U> {

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.key);
            let h = @Handler{handle: *p, prev: prev};
            move Trap { cond: self, handler: h }
        }
    }

    fn raise(t:&T) -> U  {
        do self.raise_default(t) {
            fail fmt!("Unhandled condition: %s: %?",
                      self.name,
                      t);
        }
    }

    fn raise_default(t:&T, default: fn() -> U) -> U {
        unsafe {
            match task::local_data::local_data_pop(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    default()
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    match handler.prev {
                        None => (),
                        Some(hp) =>
                        task::local_data::local_data_set(self.key, hp)
                    }
                    let handle : &fn(&T) -> U =
                        ::cast::transmute(handler.handle);
                    let u = handle(t);
                    task::local_data::local_data_set(self.key,
                                                     handler);
                    move u
                }
            }
        }
    }
}

struct Trap<T, U> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U> Trap<T,U> {
    fn in<V>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let _g = Guard { cond: self.cond };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

struct Guard<T, U> {
    cond: &Condition<T,U>,
    drop {
        unsafe {
            debug!("Guard: popping handler from TLS");
            let curr = task::local_data::local_data_pop(self.cond.key);
            match curr {
                None => (),
                Some(h) =>
                match h.prev {
                    None => (),
                    Some(hp) => {
                        task::local_data::local_data_set(self.cond.key, hp)
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    condition! {
        sadness: int -> int;
    }

    fn trouble(i: int) {
        debug!("trouble: raising conition");
        let j = sadness::cond.raise(&i);
        debug!("trouble: handler recovered with %d", j);
    }

    fn nested_trap_test_inner() {

        let mut inner_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_trap_test_inner: in handler");
            inner_trapped = true;
            0
        }).in {
            debug!("nested_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_trap_test_outer() {

        let mut outer_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_guard_test_outer: in protected block");
            nested_trap_test_inner();
            trouble(1);
        }

        assert outer_trapped;
    }

    fn nested_reraise_trap_test_inner() {

        let mut inner_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_reraise_trap_test_inner: in handler");
            inner_trapped = true;
            let i = 10;
            debug!("nested_reraise_trap_test_inner: handler re-raising");
            sadness::cond.raise(&i)
        }).in {
            debug!("nested_reraise_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_reraise_trap_test_outer() {

        let mut outer_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_reraise_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_reraise_trap_test_outer: in protected block");
            nested_reraise_trap_test_inner();
        }

        assert outer_trapped;
    }

    #[test]
    fn test_default() {

        let mut trapped = false;

        do sadness::cond.trap(|j| {
            debug!("test_default: in handler");
            sadness::cond.raise_default(j, || {trapped=true; 5})
        }).in {
            debug!("test_default: in protected block");
            trouble(1);
        }

        assert trapped;
    }

}
<commit_msg>clean up condition module: * use Drop trait in Guard * fix formatting * remove bare function in Condition.raise_default * use moved types instead of borrowed pointers in Condition.{raise,trap} * import common functions<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use task;
use task::local_data::{local_data_pop, local_data_set};

// helper for transmutation, shown below.
type RustClosure = (int, int);

pub struct Handler<T, U> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>,
}

pub struct Condition<T, U> {
    name: &static/str,
    key: task::local_data::LocalDataKey<Handler<T, U>>
}

impl<T, U> Condition<T, U> {
    fn trap(&self, h: &self/fn(T) -> U) -> Trap/&self<T, U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.key);
            let h = @Handler { handle: *p, prev: prev };
            Trap { cond: self, handler: h }
        }
    }

    fn raise(t: T) -> U {
        let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
        self.raise_default(t, || fail msg)
    }

    fn raise_default(t: T, default: &fn() -> U) -> U {
        unsafe {
            match local_data_pop(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    default()
                }
                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    match handler.prev {
                        None => {}
                        Some(hp) => local_data_set(self.key, hp)
                    }
                    let handle : &fn(T) -> U =
                        ::cast::transmute(handler.handle);
                    let u = handle(t);
                    local_data_set(self.key, handler);
                    u
                }
            }
        }
    }
}

struct Trap<T, U> {
    cond: &Condition<T, U>,
    handler: @Handler<T, U>
}

impl<T, U> Trap<T, U> {
    fn in<V>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let _g = Guard { cond: self.cond };
            debug!("Trap: pushing handler to TLS");
            local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

struct Guard<T, U> {
    cond: &Condition<T, U>
}

impl<T, U> Guard<T, U> : Drop {
    fn finalize(&self) {
        unsafe {
            debug!("Guard: popping handler from TLS");
            let curr = local_data_pop(self.cond.key);
            match curr {
                None => {}
                Some(h) => match h.prev {
                    None => {}
                    Some(hp) => local_data_set(self.cond.key, hp)
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    condition! {
        sadness: int -> int;
    }

    fn trouble(i: int) {
        debug!("trouble: raising condition");
        let j = sadness::cond.raise(i);
        debug!("trouble: handler recovered with %d", j);
    }

    fn nested_trap_test_inner() {
        let mut inner_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_trap_test_inner: in handler");
            inner_trapped = true;
            0
        }).in {
            debug!("nested_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_trap_test_outer() {
        let mut outer_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_guard_test_outer: in protected block");
            nested_trap_test_inner();
            trouble(1);
        }

        assert outer_trapped;
    }

    fn nested_reraise_trap_test_inner() {
        let mut inner_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_reraise_trap_test_inner: in handler");
            inner_trapped = true;
            let i = 10;
            debug!("nested_reraise_trap_test_inner: handler re-raising");
            sadness::cond.raise(i)
        }).in {
            debug!("nested_reraise_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_reraise_trap_test_outer() {
        let mut outer_trapped = false;

        do sadness::cond.trap(|_j| {
            debug!("nested_reraise_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_reraise_trap_test_outer: in protected block");
            nested_reraise_trap_test_inner();
        }

        assert outer_trapped;
    }

    #[test]
    fn test_default() {
        let mut trapped = false;

        do sadness::cond.trap(|j| {
            debug!("test_default: in handler");
            sadness::cond.raise_default(j, || { trapped=true; 5 })
        }).in {
            debug!("test_default: in protected block");
            trouble(1);
        }

        assert trapped;
    }
}
<|endoftext|>