<commit_before>use std::{
    collections::{HashMap, HashSet},
    path::{Path, PathBuf},
};

use pulldown_cmark::{escape, Event, LinkType, Tag};
use regex::{Captures, Regex};
use tracing::{event, instrument, Level};
use url::Url;

use crate::config::ResolvedConfig;
use crate::process::RenderingInput;

pub struct RenderAdapter<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> {
    pub(crate) ctx: &'a mut ProcessorContext<'a, 'c>,
    pub(crate) iter: I,
    // Table of contents
    // level, title, slug
    toc: Vec<(usize, String, String)>,
    // Cache for header slugification
    slugs_cache: HashMap<String, usize>,
}

const TOC_START: &'static str = r#"

Table of contents

"#;

const TOC_END: &'static str = r#"

"#;

impl<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> RenderAdapter<'a, 'b, 'c, I> {
    pub fn new(iter: I, ctx: &'a mut ProcessorContext<'a, 'c>) -> Self {
        Self {
            iter,
            ctx,
            toc: Vec::new(),
            slugs_cache: HashMap::new(),
        }
    }

    // Converts a header title into a slug.
    fn header_slug(&mut self, title: &str) -> String {
        let fixed_up = title
            .to_lowercase()
            .replace(" ", "-")
            .replace(|c: char| !c.is_alphanumeric(), "");
        if self.slugs_cache.contains_key(&fixed_up) {
            self.slugs_cache
                .insert(fixed_up.clone(), self.slugs_cache[&fixed_up] + 1);
            format!("{}{}", fixed_up, self.slugs_cache[&fixed_up])
        } else {
            self.slugs_cache.insert(fixed_up.clone(), 0);
            format!("{}", fixed_up)
        }
    }

    /// Sets up header links so that the TOC can be generated.
    pub fn setup_header_links(&mut self, inp: &str) -> String {
        let r = Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap();
        r.replace_all(inp, |caps: &Captures| {
            let level = caps[1]
                .parse::<usize>()
                .expect("Only numbers can be parsed here");
            let text = &caps[2];
            let slug = self.header_slug(&text);
            self.toc.push((level, text.to_string(), slug.clone()));
            format!(r#"<h{0} id="{1}">{2}</h{0}>"#, level, slug, text)
        })
        .into_owned()
    }

    /// Renders the table of contents
    /// and adds "toc" to the styles if necessary
    pub fn render_toc(&mut self) -> String {
        if self.toc.is_empty() {
            return String::new();
        }
        self.ctx.styles.insert("toc");
        self.ctx.styles.insert("link");
        let mut s = String::new();
        s.push_str(TOC_START);
        let mut last_level = 0;
        for (level, title, slug) in std::mem::take(&mut self.toc) {
            if level > last_level {
                s.push_str("
");
            }
            if level < last_level {
                s.push_str("
");
            }
            let escaped_slug = {
                let mut escaped = String::new();
                escape::escape_href(&mut escaped, &slug).unwrap();
                escaped
            };
            let escaped_title = {
                let mut escaped = String::new();
                escape::escape_html(&mut escaped, &title).unwrap();
                escaped
            };
            s.push_str(&format!(
                "
{}
",
                escaped_slug, escaped_title
            ));
            last_level = level;
        }
        for _ in 0..last_level {
            s.push_str("
");
        }
        s.push_str(TOC_END);
        s
    }
}

impl<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> Iterator for RenderAdapter<'a, 'b, 'c, I> {
    type Item = Event<'b>;

    #[instrument(name = "process", skip(self))]
    fn next(&mut self) -> Option<Self::Item> {
        let mut item = self.iter.next()?;
        let styles = &mut self.ctx.styles;
        let new_stack = &mut *self.ctx.new_stack;
        let render_stack = &mut *self.ctx.render_stack;
        let finished = self.ctx.finished;
        let out_dir = &self.ctx.config.roots.output;
        let base_dir = &self.ctx.config.roots.source;
        let filename = self.ctx.filename;
        if let Event::Start(Tag::Image(..)) = item {
            styles.insert("image");
        }
        if let Event::Start(Tag::Image(LinkType::Inline, ref mut url, _)) = item {
            if let Ok(parsed) = Url::parse(&url) {
                use sha2::Digest;
                let hashname = format!("{:x}", sha2::Sha256::digest(parsed.as_str().as_bytes()));
                let new_url = format!("/images/{}.webp", hashname);
                let input = RenderingInput::Image {
                    input: parsed,
                    output: hashname,
                };
                if !render_stack.contains(&input) && !finished.contains(&input) {
                    render_stack.insert(input.clone());
                    new_stack.push(input);
                }
                *url = new_url.into();
            }
        }
        if let Event::Start(Tag::Paragraph) = item {
            styles.insert("paragraph");
        }
        if let Event::Start(Tag::Heading(level)) = item {
            match level {
                1 => {
                    styles.insert("h1");
                }
                _ => {}
            }
        }
        if let Event::Start(Tag::Link(..)) = item {
            styles.insert("link");
        }
        if let Event::Start(Tag::Link(LinkType::Inline, ref mut url, _)) = item {
            if let Ok(parsed) = Url::parse(&url) {
                // check if scheme is hyperref, if so add to stack and rewrite url
                if parsed.scheme() == "hyperref" {
                    let parsed_path: &Path = parsed.path().as_ref();
                    let fname: PathBuf = if parsed_path.is_absolute() {
                        out_dir.join(parsed_path.strip_prefix("/").unwrap())
                    } else {
                        filename
                            .parent()
                            .unwrap_or("/".as_ref())
                            .join(parsed.path())
                    }
                    .with_extension("md");
                    #[cfg(target_os = "windows")]
                    // replace with backslashes so that \\?\ isn't broken
                    let fname: PathBuf = fname.to_str().unwrap().replace("/", "\\").into();
                    if let Ok(fname) = fname.canonicalize() {
                        let fname_for_url = fname.strip_prefix(&base_dir).unwrap();
                        #[cfg(target_os = "windows")]
                        // windows is dumb again
                        let fname_for_url: PathBuf =
                            fname_for_url.to_str().unwrap().replace("\\", "/").into();
                        // figure out new location
                        let new_location = format!(
                            "/{}",
                            fname_for_url.with_extension("html").to_str().unwrap(),
                        );
                        let input = RenderingInput::Page(fname);
                        if !render_stack.contains(&input) && !finished.contains(&input) {
                            match input {
                                RenderingInput::Page(ref fname) => {
                                    event!(Level::INFO, r#type = "walk", ?fname)
                                }
                                _ => {}
                            }
                            render_stack.insert(input.clone());
                            new_stack.push(input);
                        }
                        *url = new_location.into();
                    } else {
                        event!(Level::WARN, r#type = "invalid_hyperref", %url);
                    }
                }
            }
        }
        Some(item)
    }
}

/// Processing context for a single file
pub struct ProcessorContext<'a, 'b: 'a> {
    pub(crate) styles: &'a mut HashSet<&'b str>,
    pub(crate) filename: &'a Path,
    pub(crate) config: &'a ResolvedConfig,
    pub(crate) finished: &'a HashSet<RenderingInput>,
    pub(crate) render_stack: &'a mut HashSet<RenderingInput>,
    pub(crate) new_stack: &'a mut Vec<RenderingInput>,
}
<commit_msg>fix header slugification<commit_after>use std::{
    collections::{HashMap, HashSet},
    path::{Path, PathBuf},
};

use pulldown_cmark::{escape, Event, LinkType, Tag};
use regex::{Captures, Regex};
use tracing::{event, instrument, Level};
use url::Url;

use crate::config::ResolvedConfig;
use crate::process::RenderingInput;

pub struct RenderAdapter<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> {
    pub(crate) ctx: &'a mut ProcessorContext<'a, 'c>,
    pub(crate) iter: I,
    // Table of contents
    // level, title, slug
    toc: Vec<(usize, String, String)>,
    // Cache for header slugification
    slugs_cache: HashMap<String, usize>,
}

const TOC_START: &'static str = r#"

Table of contents

"#;

const TOC_END: &'static str = r#"

"#;

impl<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> RenderAdapter<'a, 'b, 'c, I> {
    pub fn new(iter: I, ctx: &'a mut ProcessorContext<'a, 'c>) -> Self {
        Self {
            iter,
            ctx,
            toc: Vec::new(),
            slugs_cache: HashMap::new(),
        }
    }

    // Converts a header title into a slug.
    fn header_slug(&mut self, title: &str) -> String {
        let fixed_up = title
            .to_lowercase()
            .replace(" ", "-")
            .replace(|c: char| !c.is_alphanumeric() && c != '-', "");
        if self.slugs_cache.contains_key(&fixed_up) {
            self.slugs_cache
                .insert(fixed_up.clone(), self.slugs_cache[&fixed_up] + 1);
            format!("{}{}", fixed_up, self.slugs_cache[&fixed_up])
        } else {
            self.slugs_cache.insert(fixed_up.clone(), 0);
            format!("{}", fixed_up)
        }
    }

    /// Sets up header links so that the TOC can be generated.
    pub fn setup_header_links(&mut self, inp: &str) -> String {
        let r = Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap();
        r.replace_all(inp, |caps: &Captures| {
            let level = caps[1]
                .parse::<usize>()
                .expect("Only numbers can be parsed here");
            let text = &caps[2];
            let slug = self.header_slug(&text);
            self.toc.push((level, text.to_string(), slug.clone()));
            format!(r#"<h{0} id="{1}">{2}</h{0}>"#, level, slug, text)
        })
        .into_owned()
    }

    /// Renders the table of contents
    /// and adds "toc" to the styles if necessary
    pub fn render_toc(&mut self) -> String {
        if self.toc.is_empty() {
            return String::new();
        }
        self.ctx.styles.insert("toc");
        self.ctx.styles.insert("link");
        let mut s = String::new();
        s.push_str(TOC_START);
        let mut last_level = 0;
        for (level, title, slug) in std::mem::take(&mut self.toc) {
            if level > last_level {
                s.push_str("
");
            }
            if level < last_level {
                s.push_str("
");
            }
            let escaped_slug = {
                let mut escaped = String::new();
                escape::escape_href(&mut escaped, &slug).unwrap();
                escaped
            };
            let escaped_title = {
                let mut escaped = String::new();
                escape::escape_html(&mut escaped, &title).unwrap();
                escaped
            };
            s.push_str(&format!(
                "
{}
",
                escaped_slug, escaped_title
            ));
            last_level = level;
        }
        for _ in 0..last_level {
            s.push_str("
");
        }
        s.push_str(TOC_END);
        s
    }
}

impl<'a, 'b, 'c: 'a, I: Iterator<Item = Event<'b>>> Iterator for RenderAdapter<'a, 'b, 'c, I> {
    type Item = Event<'b>;

    #[instrument(name = "process", skip(self))]
    fn next(&mut self) -> Option<Self::Item> {
        let mut item = self.iter.next()?;
        let styles = &mut self.ctx.styles;
        let new_stack = &mut *self.ctx.new_stack;
        let render_stack = &mut *self.ctx.render_stack;
        let finished = self.ctx.finished;
        let out_dir = &self.ctx.config.roots.output;
        let base_dir = &self.ctx.config.roots.source;
        let filename = self.ctx.filename;
        if let Event::Start(Tag::Image(..)) = item {
            styles.insert("image");
        }
        if let Event::Start(Tag::Image(LinkType::Inline, ref mut url, _)) = item {
            if let Ok(parsed) = Url::parse(&url) {
                use sha2::Digest;
                let hashname = format!("{:x}", sha2::Sha256::digest(parsed.as_str().as_bytes()));
                let new_url = format!("/images/{}.webp", hashname);
                let input = RenderingInput::Image {
                    input: parsed,
                    output: hashname,
                };
                if !render_stack.contains(&input) && !finished.contains(&input) {
                    render_stack.insert(input.clone());
                    new_stack.push(input);
                }
                *url = new_url.into();
            }
        }
        if let Event::Start(Tag::Paragraph) = item {
            styles.insert("paragraph");
        }
        if let Event::Start(Tag::Heading(level)) = item {
            match level {
                1 => {
                    styles.insert("h1");
                }
                _ => {}
            }
        }
        if let Event::Start(Tag::Link(..)) = item {
            styles.insert("link");
        }
        if let Event::Start(Tag::Link(LinkType::Inline, ref mut url, _)) = item {
            if let Ok(parsed) = Url::parse(&url) {
                // check if scheme is hyperref, if so add to stack and rewrite url
                if parsed.scheme() == "hyperref" {
                    let parsed_path: &Path = parsed.path().as_ref();
                    let fname: PathBuf = if parsed_path.is_absolute() {
                        out_dir.join(parsed_path.strip_prefix("/").unwrap())
                    } else {
                        filename
                            .parent()
                            .unwrap_or("/".as_ref())
                            .join(parsed.path())
                    }
                    .with_extension("md");
                    #[cfg(target_os = "windows")]
                    // replace with backslashes so that \\?\ isn't broken
                    let fname: PathBuf = fname.to_str().unwrap().replace("/", "\\").into();
                    if let Ok(fname) = fname.canonicalize() {
                        let fname_for_url = fname.strip_prefix(&base_dir).unwrap();
                        #[cfg(target_os = "windows")]
                        // windows is dumb again
                        let fname_for_url: PathBuf =
                            fname_for_url.to_str().unwrap().replace("\\", "/").into();
                        // figure out new location
                        let new_location = format!(
                            "/{}",
                            fname_for_url.with_extension("html").to_str().unwrap(),
                        );
                        let input = RenderingInput::Page(fname);
                        if !render_stack.contains(&input) && !finished.contains(&input) {
                            match input {
                                RenderingInput::Page(ref fname) => {
                                    event!(Level::INFO, r#type = "walk", ?fname)
                                }
                                _ => {}
                            }
                            render_stack.insert(input.clone());
                            new_stack.push(input);
                        }
                        *url = new_location.into();
                    } else {
                        event!(Level::WARN, r#type = "invalid_hyperref", %url);
                    }
                }
            }
        }
        Some(item)
    }
}

/// Processing context for a single file
pub struct ProcessorContext<'a, 'b: 'a> {
    pub(crate) styles: &'a mut HashSet<&'b str>,
    pub(crate) filename: &'a Path,
    pub(crate) config: &'a ResolvedConfig,
    pub(crate) finished: &'a HashSet<RenderingInput>,
    pub(crate) render_stack: &'a mut HashSet<RenderingInput>,
    pub(crate) new_stack: &'a mut Vec<RenderingInput>,
}
<|endoftext|>


<commit_before>/// Implements `Encode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Encode` for some type that implements a
/// `From` conversion into another type that already has `Encode` implemented.
#[macro_export]
macro_rules! impl_encode_via_from {
    ($impl_type: ty, $from_type: ty) => {
        impl ssz::Encode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Encode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Encode>::ssz_fixed_len()
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                let conv: $from_type = self.clone().into();

                conv.ssz_append(buf)
            }
        }
    };
}

/// Implements `Decode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Decode` for some type that implements a
/// `From` conversion into another type that already has `Decode` implemented.
#[macro_export]
macro_rules! impl_decode_via_from {
    ($impl_type: ty, $from_type: tt) => {
        impl ssz::Decode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Decode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Decode>::ssz_fixed_len()
            }

            fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
                $from_type::from_ssz_bytes(bytes).and_then(|dec| Ok(dec.into()))
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use crate as ssz;
    use ssz::{Decode, Encode};

    #[derive(PartialEq, Debug, Clone, Copy)]
    struct Wrapper(u64);

    impl From<u64> for Wrapper {
        fn from(x: u64) -> Wrapper {
            Wrapper(x)
        }
    }

    impl From<Wrapper> for u64 {
        fn from(x: Wrapper) -> u64 {
            x.0
        }
    }

    impl_encode_via_from!(Wrapper, u64);
    impl_decode_via_from!(Wrapper, u64);

    #[test]
    fn impl_encode_via_from() {
        let check_encode = |a: u64, b: Wrapper| assert_eq!(a.as_ssz_bytes(), b.as_ssz_bytes());

        check_encode(0, Wrapper(0));
        check_encode(1, Wrapper(1));
        check_encode(42, Wrapper(42));
    }

    #[test]
    fn impl_decode_via_from() {
        let check_decode = |bytes: Vec<u8>| {
            let a = u64::from_ssz_bytes(&bytes).unwrap();
            let b = Wrapper::from_ssz_bytes(&bytes).unwrap();

            assert_eq!(a, b.into())
        };

        check_decode(vec![0, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 2, 0, 0, 0]);
    }
}
<commit_msg>`ssz` is ambiguous (name vs any other name during import resolution)<commit_after>/// Implements `Encode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Encode` for some type that implements a
/// `From` conversion into another type that already has `Encode` implemented.
#[macro_export]
macro_rules! impl_encode_via_from {
    ($impl_type: ty, $from_type: ty) => {
        impl ssz::Encode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Encode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Encode>::ssz_fixed_len()
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                let conv: $from_type = self.clone().into();

                conv.ssz_append(buf)
            }
        }
    };
}

/// Implements `Decode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Decode` for some type that implements a
/// `From` conversion into another type that already has `Decode` implemented.
#[macro_export]
macro_rules! impl_decode_via_from {
    ($impl_type: ty, $from_type: tt) => {
        impl ssz::Decode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Decode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Decode>::ssz_fixed_len()
            }

            fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
                $from_type::from_ssz_bytes(bytes).and_then(|dec| Ok(dec.into()))
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use crate as ssz;
    use self::ssz::{Decode, Encode};

    #[derive(PartialEq, Debug, Clone, Copy)]
    struct Wrapper(u64);

    impl From<u64> for Wrapper {
        fn from(x: u64) -> Wrapper {
            Wrapper(x)
        }
    }

    impl From<Wrapper> for u64 {
        fn from(x: Wrapper) -> u64 {
            x.0
        }
    }

    impl_encode_via_from!(Wrapper, u64);
    impl_decode_via_from!(Wrapper, u64);

    #[test]
    fn impl_encode_via_from() {
        let check_encode = |a: u64, b: Wrapper| assert_eq!(a.as_ssz_bytes(), b.as_ssz_bytes());

        check_encode(0, Wrapper(0));
        check_encode(1, Wrapper(1));
        check_encode(42, Wrapper(42));
    }

    #[test]
    fn impl_decode_via_from() {
        let check_decode = |bytes: Vec<u8>| {
            let a = u64::from_ssz_bytes(&bytes).unwrap();
            let b = Wrapper::from_ssz_bytes(&bytes).unwrap();

            assert_eq!(a, b.into())
        };

        check_decode(vec![0, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 2, 0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>
use super::*;

/// Private namespace of the module.
mod private
{
}

TheModule::mod_interface!
{

  protected mod
  {
    // /// mod_protected1
    // #[ doc( inline ) ]
    mod_protected1,
    mod_protected2,
  };
  orphan mod
  {
    mod_orphan1,
    mod_orphan2,
  };
  exposed mod
  {
    mod_exposed1,
    mod_exposed2
  };
  prelude mod
  {
    mod_prelude1,
    mod_prelude2
  };

}

//

include!( "../../only_test/micro_modules_two_only_test.rs" );
<commit_msg>!test<commit_after>
use super::*;

/// Private namespace of the module.
mod private
{
}

TheModule::mod_interface!
{

  protected mod
  {
    // /// mod_protected1
    // #[ doc( inline ) ]
    mod_protected1,
    mod_protected2,
  };
  orphan mod
  {
    mod_orphan1,
    mod_orphan2,
  };
  exposed mod
  {
    mod_exposed1,
    mod_exposed2
  };
  prelude mod
  {
    mod_prelude1,
    mod_prelude2
  };

}

//

include!( "../../only_test/micro_modules_two_only_test.rs" );

<|endoftext|>


<commit_before>use kay::{ActorSystem, World, External};
use compact::CVec;
use descartes::{P2, V2, Norm, Curve};
use stagemaster::combo::{Bindings, Combo2};
use stagemaster::{UserInterfaceID, Event3d, Interactable3d, Interactable3dID,
                  MSG_Interactable3d_on_event};
use stagemaster::combo::Button::*;
use stagemaster::geometry::AnyShape;
use transport::lane::{Lane, LaneID};
use planning::materialized_reality::{MaterializedReality, MaterializedRealityID};

pub mod rendering;

use super::households::HouseholdID;

#[derive(Compact, Clone)]
pub struct Building {
    id: BuildingID,
    households: CVec<HouseholdID>,
    lot: Lot,
    being_destroyed: bool,
}

use stagemaster::geometry::add_debug_line;

impl Building {
    pub fn spawn(
        id: BuildingID,
        materialized_reality: MaterializedRealityID,
        households: &CVec<HouseholdID>,
        lot: &Lot,
        world: &mut World,
    ) -> Building {
        add_debug_line(
            lot.position,
            lot.adjacent_lane_position,
            [0.5, 0.5, 0.5],
            0.0,
            world,
        );
        materialized_reality.on_building_built(lot.position, id, lot.adjacent_lane, world);
        Building {
            id,
            households: households.clone(),
            lot: lot.clone(),
            being_destroyed: false,
        }
    }

    pub fn add_household(&mut self, household: HouseholdID, world: &mut World) {
        self.households.push(household);
        // TODO: such a weird place to do this, but ok for now
        if self.households.len() == 1 {
            rendering::on_add(self, world);
        }
    }

    pub fn remove_household(&mut self, household: HouseholdID, world: &mut World) {
        let position = self.households
            .iter()
            .position(|household_here| *household_here == household)
            .expect("Tried to remove a household not in the building");
        self.households.remove(position);

        if self.being_destroyed && self.households.is_empty() {
            self.id.finally_destroy(world);
        }
    }

    pub fn destroy(&mut self, world: &mut World) {
        for household in &self.households {
            household.destroy(world);
        }

        self.being_destroyed = true;
    }

    pub fn finally_destroy(&mut self, world: &mut World) -> ::kay::Fate {
        rendering::on_destroy(self.id, world);
        ::kay::Fate::Die
    }
}

use transport::pathfinding::{RoughLocation, LocationRequesterID, PositionRequesterID,
                             RoughLocationID, MSG_RoughLocation_resolve_as_location,
                             MSG_RoughLocation_resolve_as_position};
use core::simulation::Instant;

impl RoughLocation for Building {
    fn resolve_as_location(
        &mut self,
        requester: LocationRequesterID,
        rough_location: RoughLocationID,
        instant: Instant,
        world: &mut World,
    ) {
        Into::<RoughLocationID>::into(self.lot.adjacent_lane)
            .resolve_as_location(requester, rough_location, instant, world)
    }

    fn resolve_as_position(
        &mut self,
        requester: PositionRequesterID,
        rough_location: RoughLocationID,
        world: &mut World,
    ) {
        requester.position_resolved(rough_location, self.lot.position, world)
    }
}

#[derive(Compact, Clone)]
pub struct Lot {
    pub position: P2,
    pub orientation: V2,
    pub adjacent_lane: LaneID,
    pub adjacent_lane_position: P2,
}

#[derive(Serialize, Deserialize)]
pub struct BuildingSpawnerBindings(Bindings);

impl Default for BuildingSpawnerBindings {
    fn default() -> Self {
        BuildingSpawnerBindings(Bindings::new(
            vec![("Spawn Building", Combo2::new(&[B], &[]))],
        ))
    }
}

#[derive(Compact, Clone)]
pub enum BuildingSpawnerState {
    Idle,
    Collecting(CVec<Lot>),
    CheckingBuildings(CVec<Lot>, CVec<bool>),
    CheckingLanes(CVec<Lot>, CVec<bool>),
}

#[derive(Compact, Clone)]
pub struct BuildingSpawner {
    id: BuildingSpawnerID,
    simulation: SimulationID,
    materialized_reality: MaterializedRealityID,
    bindings: External<BuildingSpawnerBindings>,
    state: BuildingSpawnerState,
}

impl BuildingSpawner {
    pub fn init(
        id: BuildingSpawnerID,
        user_interface: UserInterfaceID,
        simulation: SimulationID,
        materialized_reality: MaterializedRealityID,
        world: &mut World,
    ) -> BuildingSpawner {
        user_interface.add(id.into(), AnyShape::Everywhere, 0, world);
        user_interface.focus(id.into(), world);

        BuildingSpawner {
            id,
            simulation,
            materialized_reality,
            bindings: External::new(::ENV.load_settings("Building Spawning")),
            state: BuildingSpawnerState::Idle,
        }
    }

    pub fn found_lot(&mut self, lot: &Lot, _: &mut World) {
        if let BuildingSpawnerState::Collecting(ref mut lots) = self.state {
            lots.push(lot.clone())
        } else {
            println!("Unexpected found lot");
        }
    }

    fn spawn_building(
        materialized_reality: MaterializedRealityID,
        lot: &Lot,
        simulation: SimulationID,
        world: &mut World,
    ) {
        let building_id = BuildingID::spawn(materialized_reality, CVec::new(), lot.clone(), world);

        if building_id._raw_id.instance_id % 6 == 0 {
            let shop_id = GroceryShopID::move_into(building_id, world);
            building_id.add_household(shop_id.into(), world);
        } else {
            let family_id = FamilyID::move_into(3, building_id, simulation, world);
            building_id.add_household(family_id.into(), world);
        }
    }

    pub fn update_feasibility(&mut self, new_feasibility: &CVec<bool>, _: &mut World) {
        match self.state {
            BuildingSpawnerState::CheckingBuildings(_, ref mut feasibility) |
            BuildingSpawnerState::CheckingLanes(_, ref mut feasibility) => {
                for (old, new) in feasibility.iter_mut().zip(new_feasibility) {
                    *old = *old && *new;
                }
            }
            _ => println!("Unexpected feasibility"),
        }
    }
}

impl Interactable3d for BuildingSpawner {
    fn on_event(&mut self, event: Event3d, world: &mut World) {
        if let Event3d::Combos(combos) = event {
            self.bindings.0.do_rebinding(&combos.current);

            if self.bindings.0["Spawn Building"].is_freshly_in(&combos) {
                if let BuildingSpawnerState::Idle = self.state {
                    LaneID::global_broadcast(world).find_lot(self.id, world);
                    self.simulation.wake_up_in(Ticks(10), self.id.into(), world);
                    self.state = BuildingSpawnerState::Collecting(CVec::new());
                }
            }
        };
    }
}

const MIN_BUILDING_DISTANCE: f32 = 20.0;

trait LotConflictor {
    fn find_conflicts(&mut self, lots: &CVec<Lot>, requester: BuildingSpawnerID, world: &mut World);
}

impl LotConflictor for Building {
    fn find_conflicts(
        &mut self,
        lots: &CVec<Lot>,
        requester: BuildingSpawnerID,
        world: &mut World,
    ) {
        requester.update_feasibility(
            lots.iter()
                .map(|lot| {
                    (lot.position - self.lot.position).norm() > MIN_BUILDING_DISTANCE
                })
                .collect(),
            world,
        )
    }
}

const MIN_LANE_BUILDING_DISTANCE: f32 = 15.0;

impl LotConflictor for Lane {
    fn find_conflicts(
        &mut self,
        lots: &CVec<Lot>,
        requester: BuildingSpawnerID,
        world: &mut World,
    ) {
        requester.update_feasibility(
            lots.iter()
                .map(|lot| {
                    self.construction.path.distance_to(lot.position) > MIN_LANE_BUILDING_DISTANCE
                })
                .collect(),
            world,
        )
    }
}

use core::simulation::{Sleeper, SleeperID, MSG_Sleeper_wake};

impl Sleeper for BuildingSpawner {
    fn wake(&mut self, _time: Instant, world: &mut World) {
        self.state = match self.state {
            BuildingSpawnerState::Collecting(ref mut lots) => {
                let buildings: LotConflictorID = BuildingID::global_broadcast(world).into();
                let mut nonconflicting_lots = CVec::<Lot>::new();
                for lot in lots.iter() {
                    let far_from_all = nonconflicting_lots.iter().all(|other_lot| {
                        (lot.position - other_lot.position).norm() > MIN_BUILDING_DISTANCE
                    });
                    if far_from_all {
                        nonconflicting_lots.push(lot.clone());
                    }
                }
                buildings.find_conflicts(nonconflicting_lots.clone(), self.id, world);
                self.simulation.wake_up_in(Ticks(10), self.id.into(), world);

                let nonconclicting_lots_len = nonconflicting_lots.len();
                BuildingSpawnerState::CheckingBuildings(
                    nonconflicting_lots,
                    vec![true; nonconclicting_lots_len].into(),
                )
            }
            BuildingSpawnerState::CheckingBuildings(ref mut lots, ref mut feasible) => {
                let new_lots: CVec<_> = lots.iter()
                    .zip(feasible)
                    .filter_map(|(lot, feasible)| if *feasible {
                        Some(lot.clone())
                    } else {
                        None
                    })
                    .collect();
                let lanes = LotConflictorID { _raw_id: world.global_broadcast::<Lane>() };
                lanes.find_conflicts(new_lots.clone(), self.id, world);
                self.simulation.wake_up_in(Ticks(10), self.id.into(), world);

                let new_lots_len = new_lots.len();
                BuildingSpawnerState::CheckingLanes(new_lots, vec![true; new_lots_len].into())
            }
            BuildingSpawnerState::CheckingLanes(ref mut lots, ref mut feasible) => {
                for (lot, feasible) in lots.iter().zip(feasible) {
                    if *feasible {
                        Self::spawn_building(
                            self.materialized_reality,
                            lot,
                            self.simulation,
                            world,
                        );
                    }
                }
                BuildingSpawnerState::Idle
            }
            BuildingSpawnerState::Idle => BuildingSpawnerState::Idle,
        }
    }
}

#[derive(Compact, Clone, Default)]
pub struct BuildingPlanResultDelta {
    buildings_to_destroy: CVec<BuildingID>,
}

#[derive(Compact, Clone, Default)]
pub struct MaterializedBuildings {
    buildings: CVec<(P2, BuildingID, LaneID)>,
}

use transport::planning::road_plan::RoadPlanResultDelta;
use transport::planning::materialized_roads::MaterializedRoads;
use std::collections::HashSet;

impl MaterializedBuildings {
    pub fn delta_with_road_result_delta(
        &self,
        road_result_delta: &RoadPlanResultDelta,
        materialized_roads: &MaterializedRoads,
    ) -> BuildingPlanResultDelta {
        let all_strokes_to_create =
            road_result_delta
                .intersections
                .to_create
                .values()
                .flat_map(|intersection| intersection.strokes.iter())
                .chain(road_result_delta.trimmed_strokes.to_create.values());

        let mut buildings_to_destroy = HashSet::<BuildingID>::new();

        for stroke_to_create in all_strokes_to_create {
            for &(building_pos, building_id, _) in &self.buildings {
                if stroke_to_create.path().distance_to(building_pos) < MIN_LANE_BUILDING_DISTANCE {
                    buildings_to_destroy.insert(building_id);
                }
            }
        }

        let lane_ids_to_be_destroyed = road_result_delta
            .trimmed_strokes
            .to_destroy
            .keys()
            .map(|lane_ref| {
                materialized_roads
                    .built_trimmed_lanes
                    .get(*lane_ref)
                    .cloned()
                    .expect("Expected road to be destroyed to be built")
            })
            .collect::<Vec<_>>();

        for &(_, building_id, building_lane) in &self.buildings {
            if lane_ids_to_be_destroyed.contains(&building_lane.into()) {
                buildings_to_destroy.insert(building_id);
            }
        }

        BuildingPlanResultDelta { buildings_to_destroy: buildings_to_destroy.into_iter().collect() }
    }

    pub fn apply(&mut self, world: &mut World, result_delta: &BuildingPlanResultDelta) {
        for building_id in &result_delta.buildings_to_destroy {
            let position = self.buildings
                .iter()
                .position(|&(_, built_building_id, _)| {
                    built_building_id == *building_id
                })
                .expect("Tried to destroy a non-built building");
            self.buildings[position].1.destroy(world);
            self.buildings.remove(position);
        }
    }
}

impl MaterializedReality {
    pub fn on_building_built(&mut self, position: P2, id: BuildingID, lane: LaneID, _: &mut World) {
        self.buildings.buildings.push((position, id, lane));
    }
}

use super::households::family::FamilyID;
use super::households::grocery_shop::GroceryShopID;
use core::simulation::{SimulationID, Ticks};

pub fn setup(
    system: &mut ActorSystem,
    user_interface: UserInterfaceID,
    simulation: SimulationID,
    materialized_reality: MaterializedRealityID,
) {
    system.register::<Building>();
    system.register::<BuildingSpawner>();
    rendering::setup(system, user_interface);

    kay_auto::auto_setup(system);

    BuildingSpawnerID::init(
        user_interface,
        simulation,
        materialized_reality,
        &mut system.world(),
    );
}

mod kay_auto;
pub use self::kay_auto::*;
<commit_msg>Remove building -> lane debug line<commit_after>use kay::{ActorSystem, World, External};
use compact::CVec;
use descartes::{P2, V2, Norm, Curve};
use stagemaster::combo::{Bindings, Combo2};
use stagemaster::{UserInterfaceID, Event3d, Interactable3d, Interactable3dID,
                  MSG_Interactable3d_on_event};
use stagemaster::combo::Button::*;
use stagemaster::geometry::AnyShape;
use transport::lane::{Lane, LaneID};
use planning::materialized_reality::{MaterializedReality, MaterializedRealityID};

pub mod rendering;

use super::households::HouseholdID;

#[derive(Compact, Clone)]
pub struct Building {
    id: BuildingID,
    households: CVec<HouseholdID>,
    lot: Lot,
    being_destroyed: bool,
}

//use stagemaster::geometry::add_debug_line;

impl Building {
    pub fn spawn(
        id: BuildingID,
        materialized_reality: MaterializedRealityID,
        households: &CVec<HouseholdID>,
        lot: &Lot,
        world: &mut World,
    ) -> Building {
        // add_debug_line(
        //     lot.position,
        //     lot.adjacent_lane_position,
        //     [0.5, 0.5, 0.5],
        //     0.0,
        //     world,
        // );
        materialized_reality.on_building_built(lot.position, id, lot.adjacent_lane, world);
        Building {
            id,
            households: households.clone(),
            lot: lot.clone(),
            being_destroyed: false,
        }
    }

    pub fn add_household(&mut self, household: HouseholdID, world: &mut World) {
        self.households.push(household);
        // TODO: such a weird place to do this, but ok for now
        if self.households.len() == 1 {
            rendering::on_add(self, world);
        }
    }

    pub fn remove_household(&mut self, household: HouseholdID, world: &mut World) {
        let position = self.households
            .iter()
            .position(|household_here| *household_here == household)
            .expect("Tried to remove a household not in the building");
        self.households.remove(position);

        if self.being_destroyed && self.households.is_empty() {
            self.id.finally_destroy(world);
        }
    }

    pub fn destroy(&mut self, world: &mut World) {
        for household in &self.households {
            household.destroy(world);
        }

        self.being_destroyed = true;
    }

    pub fn finally_destroy(&mut self, world: &mut World) -> ::kay::Fate {
        rendering::on_destroy(self.id, world);
        ::kay::Fate::Die
    }
}

use transport::pathfinding::{RoughLocation, LocationRequesterID, PositionRequesterID,
                             RoughLocationID, MSG_RoughLocation_resolve_as_location,
                             MSG_RoughLocation_resolve_as_position};
use core::simulation::Instant;

impl RoughLocation for Building {
    fn resolve_as_location(
        &mut self,
        requester: LocationRequesterID,
        rough_location: RoughLocationID,
        instant: Instant,
        world: &mut World,
    ) {
        Into::<RoughLocationID>::into(self.lot.adjacent_lane)
            .resolve_as_location(requester, rough_location, instant, world)
    }

    fn resolve_as_position(
        &mut self,
        requester: PositionRequesterID,
        rough_location: RoughLocationID,
        world: &mut World,
    ) {
        requester.position_resolved(rough_location, self.lot.position, world)
    }
}

#[derive(Compact, Clone)]
pub struct Lot {
    pub position: P2,
    pub orientation: V2,
    pub adjacent_lane: LaneID,
    pub adjacent_lane_position: P2,
}

#[derive(Serialize, Deserialize)]
pub struct BuildingSpawnerBindings(Bindings);

impl Default for BuildingSpawnerBindings {
    fn default() -> Self {
        BuildingSpawnerBindings(Bindings::new(
            vec![("Spawn Building", Combo2::new(&[B], &[]))],
        ))
    }
}

#[derive(Compact, Clone)]
pub enum BuildingSpawnerState {
    Idle,
    Collecting(CVec<Lot>),
    CheckingBuildings(CVec<Lot>, CVec<bool>),
    CheckingLanes(CVec<Lot>, CVec<bool>),
}

#[derive(Compact, Clone)]
pub struct BuildingSpawner {
    id: BuildingSpawnerID,
    simulation: SimulationID,
    materialized_reality: MaterializedRealityID,
    bindings: External<BuildingSpawnerBindings>,
    state: BuildingSpawnerState,
}

impl BuildingSpawner {
    pub fn init(
        id: BuildingSpawnerID,
        user_interface: UserInterfaceID,
        simulation: SimulationID,
        materialized_reality: MaterializedRealityID,
        world: &mut World,
    ) -> BuildingSpawner {
        user_interface.add(id.into(), AnyShape::Everywhere, 0, world);
        user_interface.focus(id.into(), world);

        BuildingSpawner {
            id,
            simulation,
            materialized_reality,
            bindings: External::new(::ENV.load_settings("Building Spawning")),
            state: BuildingSpawnerState::Idle,
        }
    }

    pub fn found_lot(&mut self, lot: &Lot, _: &mut World) {
        if let BuildingSpawnerState::Collecting(ref mut lots) = self.state {
            lots.push(lot.clone())
        } else {
            println!("Unexpected found lot");
        }
    }

    fn spawn_building(
        materialized_reality: MaterializedRealityID,
        lot: &Lot,
        simulation: SimulationID,
        world: &mut World,
    ) {
        let building_id = BuildingID::spawn(materialized_reality, CVec::new(), lot.clone(), world);

        if building_id._raw_id.instance_id % 6 == 0 {
            let shop_id = GroceryShopID::move_into(building_id, world);
            building_id.add_household(shop_id.into(), world);
        } else {
            let family_id = FamilyID::move_into(3, building_id, simulation, world);
            building_id.add_household(family_id.into(), world);
        }
    }

    pub fn update_feasibility(&mut self, new_feasibility: &CVec<bool>, _: &mut World) {
        match self.state {
            BuildingSpawnerState::CheckingBuildings(_, ref mut feasibility) |
            BuildingSpawnerState::CheckingLanes(_, ref mut feasibility) => {
                for (old, new) in feasibility.iter_mut().zip(new_feasibility) {
                    *old = *old && *new;
                }
            }
            _ => println!("Unexpected feasibility"),
        }
    }
}

impl Interactable3d for BuildingSpawner {
    fn on_event(&mut self, event: Event3d, world: &mut World) {
        if let Event3d::Combos(combos) = event {
            self.bindings.0.do_rebinding(&combos.current);

            if self.bindings.0["Spawn Building"].is_freshly_in(&combos) {
                if let BuildingSpawnerState::Idle = self.state {
                    LaneID::global_broadcast(world).find_lot(self.id, world);
                    self.simulation.wake_up_in(Ticks(10), self.id.into(), world);
                    self.state = BuildingSpawnerState::Collecting(CVec::new());
                }
            }
        };
    }
}

const MIN_BUILDING_DISTANCE: f32 = 20.0;

trait LotConflictor {
    fn find_conflicts(&mut self, lots: &CVec<Lot>, requester: BuildingSpawnerID, world: &mut World);
}

impl LotConflictor for Building {
    fn find_conflicts(
        &mut self,
        lots: &CVec<Lot>,
        requester: BuildingSpawnerID,
        world: &mut World,
    ) {
        requester.update_feasibility(
            lots.iter()
                .map(|lot| {
                    (lot.position - self.lot.position).norm() > MIN_BUILDING_DISTANCE
                })
                .collect(),
            world,
        )
    }
}

const MIN_LANE_BUILDING_DISTANCE: f32 = 15.0;

impl LotConflictor for Lane {
    fn find_conflicts(
        &mut self,
        lots: &CVec<Lot>,
        requester: BuildingSpawnerID,
        world: &mut World,
    ) {
        requester.update_feasibility(
            lots.iter()
                .map(|lot| {
                    self.construction.path.distance_to(lot.position) > MIN_LANE_BUILDING_DISTANCE
                })
                .collect(),
            world,
        )
    }
}

use core::simulation::{Sleeper, SleeperID, MSG_Sleeper_wake};

impl Sleeper for BuildingSpawner {
    fn wake(&mut self, _time: Instant, world: &mut World) {
        self.state = match self.state {
            BuildingSpawnerState::Collecting(ref mut lots) => {
                let buildings: LotConflictorID = BuildingID::global_broadcast(world).into();
                let mut nonconflicting_lots = CVec::<Lot>::new();
                for lot in lots.iter() {
                    let far_from_all = nonconflicting_lots.iter().all(|other_lot| {
                        (lot.position - other_lot.position).norm() > MIN_BUILDING_DISTANCE
                    });
                    if far_from_all {
                        nonconflicting_lots.push(lot.clone());
                    }
                }
                buildings.find_conflicts(nonconflicting_lots.clone(), self.id, world);
                self.simulation.wake_up_in(Ticks(10), self.id.into(), world);

                let nonconclicting_lots_len = nonconflicting_lots.len();
                BuildingSpawnerState::CheckingBuildings(
                    nonconflicting_lots,
                    vec![true; nonconclicting_lots_len].into(),
                )
            }
            BuildingSpawnerState::CheckingBuildings(ref mut lots, ref mut feasible) => {
                let new_lots: CVec<_> = lots.iter()
                    .zip(feasible)
                    .filter_map(|(lot, feasible)| if *feasible {
                        Some(lot.clone())
                    } else {
                        None
                    })
                    .collect();
                let lanes = LotConflictorID { _raw_id: world.global_broadcast::<Lane>() };
                lanes.find_conflicts(new_lots.clone(), self.id, world);
                self.simulation.wake_up_in(Ticks(10), self.id.into(), world);

                let new_lots_len = new_lots.len();
                BuildingSpawnerState::CheckingLanes(new_lots, vec![true; new_lots_len].into())
            }
            BuildingSpawnerState::CheckingLanes(ref mut lots, ref mut feasible) => {
                for (lot, feasible) in lots.iter().zip(feasible) {
                    if *feasible {
                        Self::spawn_building(
                            self.materialized_reality,
                            lot,
                            self.simulation,
                            world,
                        );
                    }
                }
                BuildingSpawnerState::Idle
            }
            BuildingSpawnerState::Idle => BuildingSpawnerState::Idle,
        }
    }
}

#[derive(Compact, Clone, Default)]
pub struct BuildingPlanResultDelta {
    buildings_to_destroy: CVec<BuildingID>,
}

#[derive(Compact, Clone, Default)]
pub struct MaterializedBuildings {
    buildings: CVec<(P2, BuildingID, LaneID)>,
}

use transport::planning::road_plan::RoadPlanResultDelta;
use transport::planning::materialized_roads::MaterializedRoads;
use std::collections::HashSet;

impl MaterializedBuildings {
    pub fn delta_with_road_result_delta(
        &self,
        road_result_delta: &RoadPlanResultDelta,
        materialized_roads: &MaterializedRoads,
    ) -> BuildingPlanResultDelta {
        let all_strokes_to_create =
            road_result_delta
                .intersections
                .to_create
                .values()
                .flat_map(|intersection| intersection.strokes.iter())
                .chain(road_result_delta.trimmed_strokes.to_create.values());

        let mut buildings_to_destroy = HashSet::<BuildingID>::new();

        for stroke_to_create in all_strokes_to_create {
            for &(building_pos, building_id, _) in &self.buildings {
                if stroke_to_create.path().distance_to(building_pos) < MIN_LANE_BUILDING_DISTANCE {
                    buildings_to_destroy.insert(building_id);
                }
            }
        }

        let lane_ids_to_be_destroyed = road_result_delta
            .trimmed_strokes
            .to_destroy
            .keys()
            .map(|lane_ref| {
                materialized_roads
                    .built_trimmed_lanes
                    .get(*lane_ref)
                    .cloned()
                    .expect("Expected road to be destroyed to be built")
            })
            .collect::<Vec<_>>();

        for &(_, building_id, building_lane) in &self.buildings {
            if lane_ids_to_be_destroyed.contains(&building_lane.into()) {
                buildings_to_destroy.insert(building_id);
            }
        }

        BuildingPlanResultDelta { buildings_to_destroy: buildings_to_destroy.into_iter().collect() }
    }

    pub fn apply(&mut self, world: &mut World, result_delta: &BuildingPlanResultDelta) {
        for building_id in &result_delta.buildings_to_destroy {
            let position = self.buildings
                .iter()
                .position(|&(_, built_building_id, _)| {
                    built_building_id == *building_id
                })
                .expect("Tried to destroy a non-built building");
            self.buildings[position].1.destroy(world);
            self.buildings.remove(position);
        }
    }
}

impl MaterializedReality {
    pub fn on_building_built(&mut self, position: P2, id: BuildingID, lane: LaneID, _: &mut World) {
        self.buildings.buildings.push((position, id, lane));
    }
}

use super::households::family::FamilyID;
use super::households::grocery_shop::GroceryShopID;
use core::simulation::{SimulationID, Ticks};

pub fn setup(
    system: &mut ActorSystem,
    user_interface: UserInterfaceID,
    simulation: SimulationID,
    materialized_reality: MaterializedRealityID,
) {
    system.register::<Building>();
    system.register::<BuildingSpawner>();
    rendering::setup(system, user_interface);

    kay_auto::auto_setup(system);

    BuildingSpawnerID::init(
        user_interface,
        simulation,
        materialized_reality,
        &mut system.world(),
    );
}

mod kay_auto;
pub use self::kay_auto::*;
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::fmt;

use utf8_ranges::{Utf8Range, Utf8Sequences};

use crate::automaton::Automaton;

const STATE_LIMIT: usize = 10_000; // currently at least 20MB >_<

/// An error that occurred while building a Levenshtein automaton.
///
/// This error is only defined when the `levenshtein` crate feature is enabled.
#[derive(Debug)]
pub enum LevenshteinError {
    /// If construction of the automaton reaches some hard-coded limit
    /// on the number of states, then this error is returned.
    ///
    /// The number given is the limit that was exceeded.
    TooManyStates(usize),
}

impl fmt::Display for LevenshteinError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LevenshteinError::TooManyStates(size_limit) => write!(
                f,
                "Levenshtein automaton exceeds size limit of \
                           {} states",
                size_limit
            ),
        }
    }
}

impl std::error::Error for LevenshteinError {}

/// A Unicode aware Levenshtein automaton for running efficient fuzzy queries.
///
/// This is only defined when the `levenshtein` crate feature is enabled.
///
/// A Levenshtein automata is one way to search any finite state transducer
/// for keys that *approximately* match a given query. A Levenshtein automaton
/// approximates this by returning all keys within a certain edit distance of
/// the query. The edit distance is defined by the number of insertions,
/// deletions and substitutions required to turn the query into the key.
/// Insertions, deletions and substitutions are based on
/// **Unicode characters** (where each character is a single Unicode scalar
/// value).
///
/// # Example
///
/// This example shows how to find all keys within an edit distance of `1`
/// from `foo`.
///
/// ```rust
/// use fst::automaton::Levenshtein;
/// use fst::{IntoStreamer, Streamer, Set};
///
/// fn main() {
///     let keys = vec!["fa", "fo", "fob", "focus", "foo", "food", "foul"];
///     let set = Set::from_iter(keys).unwrap();
///
///     let lev = Levenshtein::new("foo", 1).unwrap();
///     let mut stream = set.search(&lev).into_stream();
///
///     let mut keys = vec![];
///     while let Some(key) = stream.next() {
///         keys.push(key.to_vec());
///     }
///     assert_eq!(keys, vec![
///         "fo".as_bytes(),   // 1 deletion
///         "fob".as_bytes(),  // 1 substitution
///         "foo".as_bytes(),  // 0 insertions/deletions/substitutions
///         "food".as_bytes(), // 1 insertion
///     ]);
/// }
/// ```
///
/// This example only uses ASCII characters, but it will work equally well
/// on Unicode characters.
///
/// # Warning: experimental
///
/// While executing this Levenshtein automaton against a finite state
/// transducer will be very fast, *constructing* an automaton may not be.
/// Namely, this implementation is a proof of concept. While I believe the
/// algorithmic complexity is not exponential, the implementation is not speedy
/// and it can use enormous amounts of memory (tens of MB before a hard-coded
/// limit will cause an error to be returned).
///
/// This is important functionality, so one should count on this implementation
/// being vastly improved in the future.
pub struct Levenshtein {
    prog: DynamicLevenshtein,
    dfa: Dfa,
}

impl Levenshtein {
    /// Create a new Levenshtein query.
    ///
    /// The query finds all matching terms that are at most `distance`
    /// edit operations from `query`. (An edit operation may be an insertion,
    /// a deletion or a substitution.)
    ///
    /// If the underlying automaton becomes too big, then an error is returned.
    ///
    /// A `Levenshtein` value satisfies the `Automaton` trait, which means it
    /// can be used with the `search` method of any finite state transducer.
    #[inline]
    pub fn new(
        query: &str,
        distance: u32,
    ) -> Result<Levenshtein, LevenshteinError> {
        let lev = DynamicLevenshtein {
            query: query.to_owned(),
            dist: distance as usize,
        };
        let dfa = DfaBuilder::new(lev.clone()).build()?;
        Ok(Levenshtein { prog: lev, dfa })
    }
}

impl fmt::Debug for Levenshtein {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Levenshtein(query: {:?}, distance: {:?})",
            self.prog.query, self.prog.dist
        )
    }
}

#[derive(Clone)]
struct DynamicLevenshtein {
    query: String,
    dist: usize,
}

impl DynamicLevenshtein {
    fn start(&self) -> Vec<usize> {
        (0..self.query.chars().count() + 1).collect()
    }

    fn is_match(&self, state: &[usize]) -> bool {
        state.last().map(|&n| n <= self.dist).unwrap_or(false)
    }

    fn can_match(&self, state: &[usize]) -> bool {
        state.iter().min().map(|&n| n <= self.dist).unwrap_or(false)
    }

    fn accept(&self, state: &[usize], chr: Option<char>) -> Vec<usize> {
        let mut next = vec![state[0] + 1];
        for (i, c) in self.query.chars().enumerate() {
            let cost = if Some(c) == chr { 0 } else { 1 };
            let v = cmp::min(
                cmp::min(next[i] + 1, state[i + 1] + 1),
                state[i] + cost,
            );
            next.push(cmp::min(v, self.dist + 1));
        }
        next
    }
}

impl Automaton for Levenshtein {
    type State = Option<usize>;

    #[inline]
    fn start(&self) -> Option<usize> {
        Some(0)
    }

    #[inline]
    fn is_match(&self, state: &Option<usize>) -> bool {
        state.map(|state| self.dfa.states[state].is_match).unwrap_or(false)
    }

    #[inline]
    fn can_match(&self, state: &Option<usize>) -> bool {
        state.is_some()
    }

    #[inline]
    fn accept(&self, state: &Option<usize>, byte: u8) -> Option<usize> {
        state.and_then(|state| self.dfa.states[state].next[byte as usize])
    }
}

#[derive(Debug)]
struct Dfa {
    states: Vec<State>,
}

struct State {
    next: [Option<usize>; 256],
    is_match: bool,
}

impl fmt::Debug for State {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "State {{")?;
        writeln!(f, "  is_match: {:?}", self.is_match)?;
        for i in 0..256 {
            if let Some(si) = self.next[i] {
                writeln!(f, "  {:?}: {:?}", i, si)?;
            }
        }
        write!(f, "}}")
    }
}

struct DfaBuilder {
    dfa: Dfa,
    lev: DynamicLevenshtein,
    cache: HashMap<Vec<usize>, usize>,
}

impl DfaBuilder {
    fn new(lev: DynamicLevenshtein) -> DfaBuilder {
        DfaBuilder {
            dfa: Dfa { states: Vec::with_capacity(16) },
            lev,
            cache: HashMap::with_capacity(1024),
        }
    }

    fn build(mut self) -> Result<Dfa, LevenshteinError> {
        let mut stack = vec![self.lev.start()];
        let mut seen = HashSet::new();
        let query = self.lev.query.clone(); // temp work around of borrowck
        while let Some(lev_state) = stack.pop() {
            let dfa_si = self.cached_state(&lev_state).unwrap();
            let mismatch = self.add_mismatch_utf8_states(dfa_si, &lev_state);
            if let Some((next_si, lev_next)) = mismatch {
                if !seen.contains(&next_si) {
                    seen.insert(next_si);
                    stack.push(lev_next);
                }
            }
            for (i, c) in query.chars().enumerate() {
                if lev_state[i] > self.lev.dist {
                    continue;
                }
                let lev_next = self.lev.accept(&lev_state, Some(c));
                let next_si = self.cached_state(&lev_next);
                if let Some(next_si) = next_si {
                    self.add_utf8_sequences(true, dfa_si, next_si, c, c);
                    if !seen.contains(&next_si) {
                        seen.insert(next_si);
                        stack.push(lev_next);
                    }
                }
            }
            if self.dfa.states.len() > STATE_LIMIT {
                return Err(LevenshteinError::TooManyStates(STATE_LIMIT));
            }
        }
        Ok(self.dfa)
    }

    fn cached_state(&mut self, lev_state: &[usize]) -> Option<usize> {
        self.cached(lev_state).map(|(si, _)| si)
    }

    fn cached(&mut self, lev_state: &[usize]) -> Option<(usize, bool)> {
        if !self.lev.can_match(lev_state) {
            return None;
        }
        Some(match self.cache.entry(lev_state.to_vec()) {
            Entry::Occupied(v) => (*v.get(), true),
            Entry::Vacant(v) => {
                let is_match = self.lev.is_match(lev_state);
                self.dfa.states.push(State { next: [None; 256], is_match });
                (*v.insert(self.dfa.states.len() - 1), false)
            }
        })
    }

    fn add_mismatch_utf8_states(
        &mut self,
        from_si: usize,
        lev_state: &[usize],
    ) -> Option<(usize, Vec<usize>)> {
        let mismatch_state = self.lev.accept(lev_state, None);
        let to_si = match self.cached(&mismatch_state) {
            None => return None,
            Some((si, _)) => si,
            // Some((si, true)) => return Some((si, mismatch_state)),
            // Some((si, false)) => si,
        };
        self.add_utf8_sequences(false, from_si, to_si, '\u{0}', '\u{10FFFF}');
        return Some((to_si, mismatch_state));
    }

    fn add_utf8_sequences(
        &mut self,
        overwrite: bool,
        from_si: usize,
        to_si: usize,
        from_chr: char,
        to_chr: char,
    ) {
        for seq in Utf8Sequences::new(from_chr, to_chr) {
            let mut fsi = from_si;
            for range in &seq.as_slice()[0..seq.len() - 1] {
                let tsi = self.new_state(false);
                self.add_utf8_range(overwrite, fsi, tsi, range);
                fsi = tsi;
            }
            self.add_utf8_range(
                overwrite,
                fsi,
                to_si,
                &seq.as_slice()[seq.len() - 1],
            );
        }
    }

    fn add_utf8_range(
        &mut self,
        overwrite: bool,
        from: usize,
        to: usize,
        range: &Utf8Range,
    ) {
        for b in range.start as usize..range.end as usize + 1 {
            if overwrite || self.dfa.states[from].next[b].is_none() {
                self.dfa.states[from].next[b] = Some(to);
            }
        }
    }

    fn new_state(&mut self, is_match: bool) -> usize {
        self.dfa.states.push(State { next: [None; 256], is_match });
        self.dfa.states.len() - 1
    }
}
<commit_msg>levenshtein: make state limit configurable<commit_after>use std::cmp;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::fmt;

use utf8_ranges::{Utf8Range, Utf8Sequences};

use crate::automaton::Automaton;

const DEFAULT_STATE_LIMIT: usize = 10_000; // currently at least 20MB >_<

/// An error that occurred while building a Levenshtein automaton.
///
/// This error is only defined when the `levenshtein` crate feature is enabled.
#[derive(Debug)]
pub enum LevenshteinError {
    /// If construction of the automaton reaches some hard-coded limit
    /// on the number of states, then this error is returned.
    ///
    /// The number given is the limit that was exceeded.
    TooManyStates(usize),
}

impl fmt::Display for LevenshteinError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LevenshteinError::TooManyStates(size_limit) => write!(
                f,
                "Levenshtein automaton exceeds size limit of \
                           {} states",
                size_limit
            ),
        }
    }
}

impl std::error::Error for LevenshteinError {}

/// A Unicode aware Levenshtein automaton for running efficient fuzzy queries.
///
/// This is only defined when the `levenshtein` crate feature is enabled.
///
/// A Levenshtein automata is one way to search any finite state transducer
/// for keys that *approximately* match a given query. A Levenshtein automaton
/// approximates this by returning all keys within a certain edit distance of
/// the query. The edit distance is defined by the number of insertions,
/// deletions and substitutions required to turn the query into the key.
/// Insertions, deletions and substitutions are based on
/// **Unicode characters** (where each character is a single Unicode scalar
/// value).
///
/// # Example
///
/// This example shows how to find all keys within an edit distance of `1`
/// from `foo`.
///
/// ```rust
/// use fst::automaton::Levenshtein;
/// use fst::{IntoStreamer, Streamer, Set};
///
/// fn main() {
///     let keys = vec!["fa", "fo", "fob", "focus", "foo", "food", "foul"];
///     let set = Set::from_iter(keys).unwrap();
///
///     let lev = Levenshtein::new("foo", 1).unwrap();
///     let mut stream = set.search(&lev).into_stream();
///
///     let mut keys = vec![];
///     while let Some(key) = stream.next() {
///         keys.push(key.to_vec());
///     }
///     assert_eq!(keys, vec![
///         "fo".as_bytes(),   // 1 deletion
///         "fob".as_bytes(),  // 1 substitution
///         "foo".as_bytes(),  // 0 insertions/deletions/substitutions
///         "food".as_bytes(), // 1 insertion
///     ]);
/// }
/// ```
///
/// This example only uses ASCII characters, but it will work equally well
/// on Unicode characters.
///
/// # Warning: experimental
///
/// While executing this Levenshtein automaton against a finite state
/// transducer will be very fast, *constructing* an automaton may not be.
/// Namely, this implementation is a proof of concept. While I believe the
/// algorithmic complexity is not exponential, the implementation is not speedy
/// and it can use enormous amounts of memory (tens of MB before a hard-coded
/// limit will cause an error to be returned).
///
/// This is important functionality, so one should count on this implementation
/// being vastly improved in the future.
pub struct Levenshtein {
    prog: DynamicLevenshtein,
    dfa: Dfa,
}

impl Levenshtein {
    /// Create a new Levenshtein query.
    ///
    /// The query finds all matching terms that are at most `distance`
    /// edit operations from `query`. (An edit operation may be an insertion,
    /// a deletion or a substitution.)
    ///
    /// If the underlying automaton becomes too big, then an error is returned.
    /// Use `new_with_limit` to raise the limit dynamically.
    ///
    /// A `Levenshtein` value satisfies the `Automaton` trait, which means it
    /// can be used with the `search` method of any finite state transducer.
    #[inline]
    pub fn new(
        query: &str,
        distance: u32,
    ) -> Result<Levenshtein, LevenshteinError> {
        let lev = DynamicLevenshtein {
            query: query.to_owned(),
            dist: distance as usize,
        };
        let dfa = DfaBuilder::new(lev.clone()).build()?;
        Ok(Levenshtein { prog: lev, dfa })
    }

    /// Create a new Levenshtein query, but pass the state limit yourself.
    ///
    /// The query finds all matching terms that are at most `distance`
    /// edit operations from `query`. (An edit operation may be an insertion,
    /// a deletion or a substitution.)
    ///
    /// If the underlying automaton becomes too big, then an error is returned.
    /// This limit can be configured with `state_limit`.
    ///
    /// A `Levenshtein` value satisfies the `Automaton` trait, which means it
    /// can be used with the `search` method of any finite state transducer.
    #[inline]
    pub fn new_with_limit(
        query: &str,
        distance: u32,
        state_limit: usize,
    ) -> Result<Levenshtein, LevenshteinError> {
        let lev = DynamicLevenshtein {
            query: query.to_owned(),
            dist: distance as usize,
        };
        let dfa =
            DfaBuilder::new(lev.clone()).build_with_limit(state_limit)?;
        Ok(Levenshtein { prog: lev, dfa })
    }
}

impl fmt::Debug for Levenshtein {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Levenshtein(query: {:?}, distance: {:?})",
            self.prog.query, self.prog.dist
        )
    }
}

#[derive(Clone)]
struct DynamicLevenshtein {
    query: String,
    dist: usize,
}

impl DynamicLevenshtein {
    fn start(&self) -> Vec<usize> {
        (0..self.query.chars().count() + 1).collect()
    }

    fn is_match(&self, state: &[usize]) -> bool {
        state.last().map(|&n| n <= self.dist).unwrap_or(false)
    }

    fn can_match(&self, state: &[usize]) -> bool {
        state.iter().min().map(|&n| n <= self.dist).unwrap_or(false)
    }

    fn accept(&self, state: &[usize], chr: Option<char>) -> Vec<usize> {
        let mut next = vec![state[0] + 1];
        for (i, c) in self.query.chars().enumerate() {
            let cost = if Some(c) == chr { 0 } else { 1 };
            let v = cmp::min(
                cmp::min(next[i] + 1, state[i + 1] + 1),
                state[i] + cost,
            );
            next.push(cmp::min(v, self.dist + 1));
        }
        next
    }
}

impl Automaton for Levenshtein {
    type State = Option<usize>;

    #[inline]
    fn start(&self) -> Option<usize> {
        Some(0)
    }

    #[inline]
    fn is_match(&self, state: &Option<usize>) -> bool {
        state.map(|state| self.dfa.states[state].is_match).unwrap_or(false)
    }

    #[inline]
    fn can_match(&self, state: &Option<usize>) -> bool {
        state.is_some()
    }

    #[inline]
    fn accept(&self, state: &Option<usize>, byte: u8) -> Option<usize> {
        state.and_then(|state| self.dfa.states[state].next[byte as usize])
    }
}

#[derive(Debug)]
struct Dfa {
    states: Vec<State>,
}

struct State {
    next: [Option<usize>; 256],
    is_match: bool,
}

impl fmt::Debug for State {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "State {{")?;
        writeln!(f, "  is_match: {:?}", self.is_match)?;
        for i in 0..256 {
            if let Some(si) = self.next[i] {
                writeln!(f, "  {:?}: {:?}", i, si)?;
            }
        }
        write!(f, "}}")
    }
}

struct DfaBuilder {
    dfa: Dfa,
    lev: DynamicLevenshtein,
    cache: HashMap<Vec<usize>, usize>,
}

impl DfaBuilder {
    fn new(lev: DynamicLevenshtein) -> DfaBuilder {
        DfaBuilder {
            dfa: Dfa { states: Vec::with_capacity(16) },
            lev,
            cache: HashMap::with_capacity(1024),
        }
    }

    fn build_with_limit(
        mut self,
        state_limit: usize,
    ) -> Result<Dfa, LevenshteinError> {
        let mut stack = vec![self.lev.start()];
        let mut seen = HashSet::new();
        let query = self.lev.query.clone(); // temp work around of borrowck
        while let Some(lev_state) = stack.pop() {
            let dfa_si = self.cached_state(&lev_state).unwrap();
            let mismatch = self.add_mismatch_utf8_states(dfa_si, &lev_state);
            if let Some((next_si, lev_next)) = mismatch {
                if !seen.contains(&next_si) {
                    seen.insert(next_si);
                    stack.push(lev_next);
                }
            }
            for (i, c) in query.chars().enumerate() {
                if lev_state[i] > self.lev.dist {
                    continue;
                }
                let lev_next = self.lev.accept(&lev_state, Some(c));
                let next_si = self.cached_state(&lev_next);
                if let Some(next_si) = next_si {
                    self.add_utf8_sequences(true, dfa_si, next_si, c, c);
                    if !seen.contains(&next_si) {
                        seen.insert(next_si);
                        stack.push(lev_next);
                    }
                }
            }
            if self.dfa.states.len() > state_limit {
                return Err(LevenshteinError::TooManyStates(state_limit));
            }
        }
        Ok(self.dfa)
    }

    fn build(mut self) -> Result<Dfa, LevenshteinError> {
        self.build_with_limit(DEFAULT_STATE_LIMIT)
    }

    fn cached_state(&mut self, lev_state: &[usize]) -> Option<usize> {
        self.cached(lev_state).map(|(si, _)| si)
    }

    fn cached(&mut self, lev_state: &[usize]) -> Option<(usize, bool)> {
        if !self.lev.can_match(lev_state) {
            return None;
        }
        Some(match self.cache.entry(lev_state.to_vec()) {
            Entry::Occupied(v) => (*v.get(), true),
            Entry::Vacant(v) => {
                let is_match = self.lev.is_match(lev_state);
                self.dfa.states.push(State { next: [None; 256], is_match });
                (*v.insert(self.dfa.states.len() - 1), false)
            }
        })
    }

    fn add_mismatch_utf8_states(
        &mut self,
        from_si: usize,
        lev_state: &[usize],
    ) -> Option<(usize, Vec<usize>)> {
        let mismatch_state = self.lev.accept(lev_state, None);
        let to_si = match self.cached(&mismatch_state) {
            None => return None,
            Some((si, _)) => si,
            // Some((si, true)) => return Some((si, mismatch_state)),
            // Some((si, false)) => si,
        };
        self.add_utf8_sequences(false, from_si, to_si, '\u{0}', '\u{10FFFF}');
        return Some((to_si, mismatch_state));
    }

    fn add_utf8_sequences(
        &mut self,
        overwrite: bool,
        from_si: usize,
        to_si: usize,
        from_chr: char,
        to_chr: char,
    ) {
        for seq in Utf8Sequences::new(from_chr, to_chr) {
            let mut fsi = from_si;
            for range in &seq.as_slice()[0..seq.len() - 1] {
                let tsi = self.new_state(false);
                self.add_utf8_range(overwrite, fsi, tsi, range);
                fsi = tsi;
            }
            self.add_utf8_range(
                overwrite,
                fsi,
                to_si,
                &seq.as_slice()[seq.len() - 1],
            );
        }
    }

    fn add_utf8_range(
        &mut self,
        overwrite: bool,
        from: usize,
        to: usize,
        range: &Utf8Range,
    ) {
        for b in range.start as usize..range.end as usize + 1 {
            if overwrite || self.dfa.states[from].next[b].is_none() {
                self.dfa.states[from].next[b] = Some(to);
            }
        }
    }

    fn new_state(&mut self, is_match: bool) -> usize {
        self.dfa.states.push(State { next: [None; 256], is_match });
        self.dfa.states.len() - 1
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! List of lists.

use traits::{FromPointerReader, FromPointerBuilder};
use private::layout::{ListReader, ListBuilder, PointerReader, PointerBuilder, Pointer};
use Result;

#[derive(Clone, Copy)]
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
    marker: ::std::marker::PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}

impl<'a, T> ::traits::Owned<'a> for Owned<T> where T: for<'b> ::traits::Owned<'b> {
    type Reader = Reader<'a, T>;
    type Builder = Builder<'a, T>;
}

#[derive(Clone, Copy)]
pub struct Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    marker: ::std::marker::PhantomData<<T as ::traits::Owned<'a>>::Reader>,
    reader: ListReader<'a>
}

impl <'a, T> Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn new<'b>(reader : ListReader<'b>) -> Reader<'b, T> {
        Reader::<'b, T> { reader : reader, marker : ::std::marker::PhantomData }
    }

    pub fn len(&self) -> u32 { self.reader.len() }
}

impl <'a, T> FromPointerReader<'a> for Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    fn get_from_pointer(reader : &PointerReader<'a>) -> Result<Reader<'a, T>> {
        Ok(Reader { reader : try!(reader.get_list(Pointer, ::std::ptr::null())),
                    marker : ::std::marker::PhantomData })
    }
}

impl <'a, T> Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn get(self, index: u32) -> Result<<T as ::traits::Owned<'a>>::Reader> {
        assert!(index <  self.len());
        FromPointerReader::get_from_pointer(&self.reader.get_pointer_element(index))
    }
}

pub struct Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    marker : ::std::marker::PhantomData<T>,
    builder : ListBuilder<'a>
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn new(builder: ListBuilder<'a>) -> Builder<'a, T> {
        Builder { builder : builder, marker : ::std::marker::PhantomData }
    }

    pub fn len(&self) -> u32 { self.builder.len() }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn init(self, index: u32, size: u32) -> <T as ::traits::Owned<'a>>::Builder {
        FromPointerBuilder::init_pointer(self.builder.get_pointer_element(index), size)
    }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn borrow<'b>(&'b mut self) -> Builder<'b, T> {
        Builder {builder : self.builder, marker : ::std::marker::PhantomData}
    }
}

impl <'a, T> FromPointerBuilder<'a> for Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    fn init_pointer(builder : PointerBuilder<'a>, size : u32) -> Builder<'a, T> {
        Builder {
            marker : ::std::marker::PhantomData,
            builder : builder.init_list(Pointer, size)
        }
    }
    fn get_from_pointer(builder : PointerBuilder<'a>) -> Result<Builder<'a, T>> {
        Ok(Builder {
            marker : ::std::marker::PhantomData,
            builder : try!(builder.get_list(Pointer, ::std::ptr::null()))
        })
    }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn get(self, index : u32) -> Result<<T as ::traits::Owned<'a>>::Builder> {
        assert!(index < self.len());
        FromPointerBuilder::get_from_pointer(self.builder.get_pointer_element(index))
    }
}

impl <'a, T> ::traits::SetPointerBuilder<Builder<'a, T>> for Reader<'a, T>
    where T: for<'b> ::traits::Owned<'b>
{
    fn set_pointer_builder<'b>(pointer : ::private::layout::PointerBuilder<'b>,
                               value : Reader<'a, T>) -> Result<()> {
        pointer.set_list(&value.reader)
    }
}

<commit_msg>Allow iterating over lists of lists.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! List of lists.

use traits::{FromPointerReader, FromPointerBuilder, ListIter, IndexMove};
use private::layout::{ListReader, ListBuilder, PointerReader, PointerBuilder, Pointer};
use Result;

#[derive(Clone, Copy)]
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
    marker: ::std::marker::PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}

impl<'a, T> ::traits::Owned<'a> for Owned<T> where T: for<'b> ::traits::Owned<'b> {
    type Reader = Reader<'a, T>;
    type Builder = Builder<'a, T>;
}

pub struct Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    marker: ::std::marker::PhantomData<<T as ::traits::Owned<'a>>::Reader>,
    reader: ListReader<'a>
}

impl <'a, T> Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn new<'b>(reader : ListReader<'b>) -> Reader<'b, T> {
        Reader::<'b, T> { reader : reader, marker : ::std::marker::PhantomData }
    }

    pub fn len(&self) -> u32 { self.reader.len() }
    pub fn iter(self) -> ListIter<Reader<'a, T>, Result<<T as ::traits::Owned<'a>>::Reader>> {
        ListIter::new(self, self.len())
    }
}

impl <'a, T> Clone for Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    fn clone(&self) -> Reader<'a, T> {
        Reader { marker : self.marker, reader : self.reader }
    }
}

impl <'a, T> Copy for Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {}

impl <'a, T>  IndexMove<u32, Result<<T as ::traits::Owned<'a>>::Reader>> for Reader<'a, T>
where T: for<'b> ::traits::Owned<'b> {
    fn index_move(&self, index : u32) -> Result<<T as ::traits::Owned<'a>>::Reader> {
        self.get(index)
    }
}

impl <'a, T> FromPointerReader<'a> for Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    fn get_from_pointer(reader : &PointerReader<'a>) -> Result<Reader<'a, T>> {
        Ok(Reader { reader : try!(reader.get_list(Pointer, ::std::ptr::null())),
                    marker : ::std::marker::PhantomData })
    }
}

impl <'a, T> Reader<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn get(self, index: u32) -> Result<<T as ::traits::Owned<'a>>::Reader> {
        assert!(index <  self.len());
        FromPointerReader::get_from_pointer(&self.reader.get_pointer_element(index))
    }
}

pub struct Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    marker : ::std::marker::PhantomData<T>,
    builder : ListBuilder<'a>
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn new(builder: ListBuilder<'a>) -> Builder<'a, T> {
        Builder { builder : builder, marker : ::std::marker::PhantomData }
    }

    pub fn len(&self) -> u32 { self.builder.len() }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn init(self, index: u32, size: u32) -> <T as ::traits::Owned<'a>>::Builder {
        FromPointerBuilder::init_pointer(self.builder.get_pointer_element(index), size)
    }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn borrow<'b>(&'b mut self) -> Builder<'b, T> {
        Builder {builder : self.builder, marker : ::std::marker::PhantomData}
    }
}

impl <'a, T> FromPointerBuilder<'a> for Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    fn init_pointer(builder : PointerBuilder<'a>, size : u32) -> Builder<'a, T> {
        Builder {
            marker : ::std::marker::PhantomData,
            builder : builder.init_list(Pointer, size)
        }
    }
    fn get_from_pointer(builder : PointerBuilder<'a>) -> Result<Builder<'a, T>> {
        Ok(Builder {
            marker : ::std::marker::PhantomData,
            builder : try!(builder.get_list(Pointer, ::std::ptr::null()))
        })
    }
}

impl <'a, T> Builder<'a, T> where T: for<'b> ::traits::Owned<'b> {
    pub fn get(self, index : u32) -> Result<<T as ::traits::Owned<'a>>::Builder> {
        assert!(index < self.len());
        FromPointerBuilder::get_from_pointer(self.builder.get_pointer_element(index))
    }
}

impl <'a, T> ::traits::SetPointerBuilder<Builder<'a, T>> for Reader<'a, T>
    where T: for<'b> ::traits::Owned<'b>
{
    fn set_pointer_builder<'b>(pointer : ::private::layout::PointerBuilder<'b>,
                               value : Reader<'a, T>) -> Result<()> {
        pointer.set_list(&value.reader)
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    body.push(' ');

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    // Prevent infinite loops from running forever
    {
        let mut context = vm.context();

        context.set_stack_size_limit(10000);

        let start = Instant::now();
        context.set_hook(Some(Box::new(move |_| {
            if start.elapsed().as_secs() < 10 {
                Ok(())
            } else {
                Err(Error::Message("Thread has exceeded the allowed exection time".into()))
            }
        })));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    Ok(format!("{:?} : {}", value, typ))
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![("name".into(), Value::String(name)),
                             ("value".into(), Value::String(contents))];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);
        let vm = RootedThread::new();

        // Ensure the import macro cannot be abused to to open files
        {
            // Ensure the lock to `paths` are released
            let import = Import::new(DefaultImporter);
            import.paths.write().unwrap().clear();
            vm.get_macros()
                .insert(String::from("import"), import);
        }

        Compiler::new()
            .implicit_prelude(false)
            .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import "std/types.glu" "#)
            .unwrap();

        gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
        gluon::io::load(&vm).expect("Loaded IO library");

        middleware.link(persistent::Read::<VMKey>::both(vm));
        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<commit_msg>refactor: Clean up and comment the server<commit_after>#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    {
        let mut context = vm.context();

        // Prevent the stack from consuming to much memory
        context.set_stack_size_limit(10000);

        // Prevent infinite loops from running forever
        let start = Instant::now();
        context.set_hook(Some(Box::new(move |_| {
            if start.elapsed().as_secs() < 10 {
                Ok(())
            } else {
                Err(Error::Message("Thread has exceeded the allowed exection time".into()))
            }
        })));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    Ok(format!("{:?} : {}", value, typ))
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

/// Load all examples into a JSON array `[{ name: .., value: .. }, ..]`
fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![("name".into(), Value::String(name)),
                             ("value".into(), Value::String(contents))];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn make_eval_vm() -> RootedThread {
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros()
            .insert(String::from("import"), import);
    }

    // Initialize the basic types such as `Bool` and `Option` so they are available when loading
    // other modules
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import "std/types.glu" "#)
        .unwrap();

    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    // Load the io library so the prelude can be loaded (`IO` actions won't actually execute however)
    gluon::io::load(&vm).expect("Loaded IO library");

    vm
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);

        let vm = make_eval_vm();
        middleware.link(persistent::Read::<VMKey>::both(vm));

        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";

    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<|endoftext|>