<commit_before>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use util::*;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox
}

pub fn draw_in_viewport<F>(vx: f64, vy: f64, vw: f64, vh: f64,
                           clip_mode: ClipMode,
                           do_clip: bool,
                           vbox: Option<ViewBox>,
                           preserve_aspect_ratio: AspectRatio,
                           affine: cairo::Matrix,
                           draw_ctx: *const RsvgDrawingCtx,
                           draw_fn: F)
    where F: FnOnce()
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(&mut ctx,
                vx, vy, vw, vh,
                clip_mode,
                do_clip,
                vbox,
                preserve_aspect_ratio,
                affine,
                draw_fn);
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self, );
    fn push_discrete_layer(&mut self);
    fn pop_discrete_layer(&mut self);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *const RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self) {
        drawing_ctx::push_discrete_layer(self.0);
    }

    fn pop_discrete_layer(&mut self) {
        drawing_ctx::pop_discrete_layer(self.0);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        drawing_ctx::add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::set_current_state_affine(self.0, affine);
    }
}

fn in_viewport<F>(ctx: &mut ViewportCtx,
                  vx: f64, vy: f64, vw: f64, vh: f64,
                  clip_mode: ClipMode,
                  do_clip: bool,
                  vbox: Option<ViewBox>,
                  preserve_aspect_ratio: AspectRatio,
                  mut affine: cairo::Matrix,
                  draw_fn: F)
    where F: FnOnce()
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if double_equals(vw, 0.0) || double_equals(vh, 0.0) {
        return;
    }

    let old_affine = affine;

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if double_equals(vbox.0.width, 0.0) || double_equals(vbox.0.height, 0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }
        let (x, y, w, h) = preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height,
                                                         vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        ctx.set_affine(affine);

        ctx.push_view_box(vbox.0.width, vbox.0.height);

        ctx.push_discrete_layer();

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        affine.translate(vx, vy);
        ctx.set_affine(affine);

        ctx.push_view_box(vw, vh);
        ctx.push_discrete_layer();
    }

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        ctx.set_affine(old_affine);
        ctx.add_clipping_rect(vx, vy, vw, vh);
        ctx.set_affine(affine);
    }

    draw_fn();

    ctx.pop_discrete_layer();
    ctx.pop_view_box();
}

#[cfg(test)]
mod tests {
    use super::*;
    use parsers::Parse;

    #[derive(Default, PartialEq)]
    struct Ctx {
        pub view_box_size: Option<(f64, f64)>,
        pub clipping_rect: Option<(f64, f64, f64, f64)>,
        pub affine:        Option<cairo::Matrix>,

        pub expected_view_box_size: Option<(f64, f64)>,
        pub expected_clipping_rect: Option<(f64, f64, f64, f64)>,
        pub expected_affine:        Option<cairo::Matrix>,
    }

    impl ViewportCtx for Ctx {
        fn push_view_box(&mut self, width: f64, height: f64) {
            self.view_box_size = Some((width, height));
        }

        fn pop_view_box(&mut self) {
        }

        fn push_discrete_layer(&mut self) {
        }

        fn pop_discrete_layer(&mut self) {
        }

        fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
            self.clipping_rect = Some((x, y, w, h));
        }

        fn set_affine(&mut self, affine: cairo::Matrix) {
            self.affine = Some(affine);
        }
    }

    fn call_in_viewport(vx: f64, vy: f64, vw: f64, vh: f64,
                        clip_mode: ClipMode,
                        do_clip: bool,
                        vbox: Option<ViewBox>,
                        preserve_aspect_ratio: AspectRatio,
                        affine: cairo::Matrix,
                        ctx: &mut Ctx) {
        in_viewport(ctx,
                    vx, vy, vw, vh,
                    clip_mode,
                    do_clip,
                    vbox,
                    preserve_aspect_ratio,
                    affine,
                    || ());

        assert_eq!(ctx.view_box_size, ctx.expected_view_box_size);
        assert_eq!(ctx.clipping_rect, ctx.expected_clipping_rect);
        assert_eq!(ctx.affine, ctx.expected_affine);
    }

    #[test]
    fn clip_after_layer_push() {
        let mut affine = cairo::Matrix::identity();
        affine.scale(0.20, 0.20);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine:        None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((10.0, 10.0, 10.0, 10.0)),
            expected_affine: Some(affine)
        };

        call_in_viewport(10.0, 10.0, 10.0, 10.0,
                         ClipMode::ClipToViewport,
                         true,
                         Some(ViewBox(cairo::Rectangle {
                             x: 50.0,
                             y: 50.0,
                             width: 50.0,
                             height: 50.0,
                         })),
                         AspectRatio::parse("xMidYMid meet", ()).unwrap(),
                         cairo::Matrix::identity(),
                         &mut ctx);
    }

    #[test]
    fn clip_before_layer_push() {
        let mut affine = cairo::Matrix::identity();
        affine.translate(10.0, 10.0);
        affine.scale(0.40, 0.40);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine:        None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((0.0, 0.0, 50.0, 50.0)),
            expected_affine: Some(affine)
        };

        call_in_viewport(10.0, 10.0, 20.0, 20.0,
                         ClipMode::ClipToVbox,
                         true,
                         Some(ViewBox(cairo::Rectangle {
                             x: 0.0,
                             y: 0.0,
                             width: 50.0,
                             height: 50.0,
                         })),
                         AspectRatio::parse("xMidYMid meet", ()).unwrap(),
                         cairo::Matrix::identity(),
                         &mut ctx);
    }
}
<commit_msg>viewport.rs: Make the order of operations consistent<commit_after>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use util::*;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox
}

pub fn draw_in_viewport<F>(vx: f64, vy: f64, vw: f64, vh: f64,
                           clip_mode: ClipMode,
                           do_clip: bool,
                           vbox: Option<ViewBox>,
                           preserve_aspect_ratio: AspectRatio,
                           affine: cairo::Matrix,
                           draw_ctx: *const RsvgDrawingCtx,
                           draw_fn: F)
    where F: FnOnce()
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(&mut ctx,
                vx, vy, vw, vh,
                clip_mode,
                do_clip,
                vbox,
                preserve_aspect_ratio,
                affine,
                draw_fn);
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self, );
    fn push_discrete_layer(&mut self);
    fn pop_discrete_layer(&mut self);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *const RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self) {
        drawing_ctx::push_discrete_layer(self.0);
    }

    fn pop_discrete_layer(&mut self) {
        drawing_ctx::pop_discrete_layer(self.0);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        drawing_ctx::add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::set_current_state_affine(self.0, affine);
    }
}

fn in_viewport<F>(ctx: &mut ViewportCtx,
                  vx: f64, vy: f64, vw: f64, vh: f64,
                  clip_mode: ClipMode,
                  do_clip: bool,
                  vbox: Option<ViewBox>,
                  preserve_aspect_ratio: AspectRatio,
                  mut affine: cairo::Matrix,
                  draw_fn: F)
    where F: FnOnce()
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if double_equals(vw, 0.0) || double_equals(vh, 0.0) {
        return;
    }

    let old_affine = affine;

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if double_equals(vbox.0.width, 0.0) || double_equals(vbox.0.height, 0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }

        ctx.push_view_box(vbox.0.width, vbox.0.height);
        ctx.push_discrete_layer();

        let (x, y, w, h) = preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height,
                                                         vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        ctx.set_affine(affine);

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        ctx.push_view_box(vw, vh);
        ctx.push_discrete_layer();

        affine.translate(vx, vy);
        ctx.set_affine(affine);
    }

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        ctx.set_affine(old_affine);
        ctx.add_clipping_rect(vx, vy, vw, vh);
        ctx.set_affine(affine);
    }

    draw_fn();

    ctx.pop_discrete_layer();
    ctx.pop_view_box();
}

#[cfg(test)]
mod tests {
    use super::*;
    use parsers::Parse;

    #[derive(Default, PartialEq)]
    struct Ctx {
        pub view_box_size: Option<(f64, f64)>,
        pub clipping_rect: Option<(f64, f64, f64, f64)>,
        pub affine:        Option<cairo::Matrix>,

        pub expected_view_box_size: Option<(f64, f64)>,
        pub expected_clipping_rect: Option<(f64, f64, f64, f64)>,
        pub expected_affine:        Option<cairo::Matrix>,
    }

    impl ViewportCtx for Ctx {
        fn push_view_box(&mut self, width: f64, height: f64) {
            self.view_box_size = Some((width, height));
        }

        fn pop_view_box(&mut self) {
        }

        fn push_discrete_layer(&mut self) {
        }

        fn pop_discrete_layer(&mut self) {
        }

        fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
            self.clipping_rect = Some((x, y, w, h));
        }

        fn set_affine(&mut self, affine: cairo::Matrix) {
            self.affine = Some(affine);
        }
    }

    fn call_in_viewport(vx: f64, vy: f64, vw: f64, vh: f64,
                        clip_mode: ClipMode,
                        do_clip: bool,
                        vbox: Option<ViewBox>,
                        preserve_aspect_ratio: AspectRatio,
                        affine: cairo::Matrix,
                        ctx: &mut Ctx) {
        in_viewport(ctx,
                    vx, vy, vw, vh,
                    clip_mode,
                    do_clip,
                    vbox,
                    preserve_aspect_ratio,
                    affine,
                    || ());

        assert_eq!(ctx.view_box_size, ctx.expected_view_box_size);
        assert_eq!(ctx.clipping_rect, ctx.expected_clipping_rect);
        assert_eq!(ctx.affine, ctx.expected_affine);
    }

    #[test]
    fn clip_after_layer_push() {
        let mut affine = cairo::Matrix::identity();
        affine.scale(0.20, 0.20);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine:        None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((10.0, 10.0, 10.0, 10.0)),
            expected_affine: Some(affine)
        };

        call_in_viewport(10.0, 10.0, 10.0, 10.0,
                         ClipMode::ClipToViewport,
                         true,
                         Some(ViewBox(cairo::Rectangle {
                             x: 50.0,
                             y: 50.0,
                             width: 50.0,
                             height: 50.0,
                         })),
                         AspectRatio::parse("xMidYMid meet", ()).unwrap(),
                         cairo::Matrix::identity(),
                         &mut ctx);
    }

    #[test]
    fn clip_before_layer_push() {
        let mut affine = cairo::Matrix::identity();
        affine.translate(10.0, 10.0);
        affine.scale(0.40, 0.40);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine:        None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((0.0, 0.0, 50.0, 50.0)),
            expected_affine: Some(affine)
        };

        call_in_viewport(10.0, 10.0, 20.0, 20.0,
                         ClipMode::ClipToVbox,
                         true,
                         Some(ViewBox(cairo::Rectangle {
                             x: 0.0,
                             y: 0.0,
                             width: 50.0,
                             height: 50.0,
                         })),
                         AspectRatio::parse("xMidYMid meet", ()).unwrap(),
                         cairo::Matrix::identity(),
                         &mut ctx);
    }
}
<|endoftext|>


<commit_before>use std::{
    ops::Deref,
    sync::{atomic::AtomicUsize, Arc, RwLock},
};

use pagecache::FastMap8;

use super::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Arc<Context>,
    default: Arc<Tree>,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Arc<Tree>>>>,
}

unsafe impl Send for Db {}

unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    pub fn start_default<P: AsRef<std::path::Path>>(
        path: P,
    ) -> Result<Db, ()> {
        let config = ConfigBuilder::new().path(path).build();
        Self::start(config)
    }

    /// Load existing or create a new `Db`.
    pub fn start(config: Config) -> Result<Db, ()> {
        let _measure = Measure::new(&M.tree_start);

        let guard = pin();

        let context = Arc::new(Context::start(config)?);

        let default = Arc::new(meta::open_tree(
            context.clone(),
            DEFAULT_TREE_ID.to_vec(),
            &guard,
        )?);

        let ret = Db {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write().unwrap();

        for (id, root) in meta::meta(&context.pagecache, &guard)?
            .tenants()
            .into_iter()
        {
            let tree = Tree {
                tree_id: id.clone(),
                subscriptions: Arc::new(Subscriptions::default()),
                context: context.clone(),
                root: Arc::new(AtomicUsize::new(root)),
            };
            tenants.insert(id, Arc::new(tree));
        }

        drop(tenants);

        #[cfg(feature = "event_log")]
        context.event_log.meta_after_restart(
            meta::meta(&context.pagecache, &guard)
                .expect("should be able to get meta under test")
                .clone(),
        );

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree(&self, name: Vec<u8>) -> Result<Arc<Tree>, ()> {
        let tenants = self.tenants.read().unwrap();
        if let Some(tree) = tenants.get(&name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let guard = pin();

        let mut tenants = self.tenants.write().unwrap();
        let tree = Arc::new(meta::open_tree(
            self.context.clone(),
            name.clone(),
            &guard,
        )?);
        tenants.insert(name, tree.clone());
        drop(tenants);
        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool, ()> {
        if name == DEFAULT_TREE_ID || name == TX_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write().unwrap();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let guard = pin();

        let mut root_id = meta::pid_for_name(
            &self.context.pagecache,
            &name,
            &guard,
        )?;

        let leftmost_chain: Vec<PageId> = tree
            .path_for_key(b"", &guard)?
            .into_iter()
            .map(|(frag, _tp)| frag.unwrap_base().id)
            .collect();

        loop {
            let res = meta::cas_root(
                &self.context.pagecache,
                name.to_vec(),
                Some(root_id),
                None,
                &guard,
            )
            .map_err(|e| e.danger_cast());

            match res {
                Ok(_) => break,
                Err(Error::CasFailed(actual)) => root_id = actual,
                Err(other) => return Err(other.danger_cast()),
            }
        }

        tree.root.store(
            usize::max_value(),
            std::sync::atomic::Ordering::SeqCst,
        );

        // drop writer lock
        drop(tenants);

        guard.defer(move || tree.gc_pages(leftmost_chain));

        guard.flush();

        Ok(true)
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<usize, ()> {
        self.context.generate_id()
    }
}
<commit_msg>make tree removal syncrhonous<commit_after>use std::{
    ops::Deref,
    sync::{atomic::AtomicUsize, Arc, RwLock},
};

use pagecache::FastMap8;

use super::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Arc<Context>,
    default: Arc<Tree>,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Arc<Tree>>>>,
}

unsafe impl Send for Db {}

unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    pub fn start_default<P: AsRef<std::path::Path>>(
        path: P,
    ) -> Result<Db, ()> {
        let config = ConfigBuilder::new().path(path).build();
        Self::start(config)
    }

    /// Load existing or create a new `Db`.
    pub fn start(config: Config) -> Result<Db, ()> {
        let _measure = Measure::new(&M.tree_start);

        let guard = pin();

        let context = Arc::new(Context::start(config)?);

        let default = Arc::new(meta::open_tree(
            context.clone(),
            DEFAULT_TREE_ID.to_vec(),
            &guard,
        )?);

        let ret = Db {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write().unwrap();

        for (id, root) in meta::meta(&context.pagecache, &guard)?
            .tenants()
            .into_iter()
        {
            let tree = Tree {
                tree_id: id.clone(),
                subscriptions: Arc::new(Subscriptions::default()),
                context: context.clone(),
                root: Arc::new(AtomicUsize::new(root)),
            };
            tenants.insert(id, Arc::new(tree));
        }

        drop(tenants);

        #[cfg(feature = "event_log")]
        context.event_log.meta_after_restart(
            meta::meta(&context.pagecache, &guard)
                .expect("should be able to get meta under test")
                .clone(),
        );

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree(&self, name: Vec<u8>) -> Result<Arc<Tree>, ()> {
        let tenants = self.tenants.read().unwrap();
        if let Some(tree) = tenants.get(&name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let guard = pin();

        let mut tenants = self.tenants.write().unwrap();
        let tree = Arc::new(meta::open_tree(
            self.context.clone(),
            name.clone(),
            &guard,
        )?);
        tenants.insert(name, tree.clone());
        drop(tenants);
        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool, ()> {
        if name == DEFAULT_TREE_ID || name == TX_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write().unwrap();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let guard = pin();

        let mut root_id = meta::pid_for_name(
            &self.context.pagecache,
            &name,
            &guard,
        )?;

        let leftmost_chain: Vec<PageId> = tree
            .path_for_key(b"", &guard)?
            .into_iter()
            .map(|(frag, _tp)| frag.unwrap_base().id)
            .collect();

        loop {
            let res = meta::cas_root(
                &self.context.pagecache,
                name.to_vec(),
                Some(root_id),
                None,
                &guard,
            )
            .map_err(|e| e.danger_cast());

            match res {
                Ok(_) => break,
                Err(Error::CasFailed(actual)) => root_id = actual,
                Err(other) => return Err(other.danger_cast()),
            }
        }

        tree.root.store(
            usize::max_value(),
            std::sync::atomic::Ordering::SeqCst,
        );

        // drop writer lock
        drop(tenants);

        tree.gc_pages(leftmost_chain)?;

        guard.flush();

        Ok(true)
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<usize, ()> {
        self.context.generate_id()
    }
}
<|endoftext|>


<commit_before>
use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id.clone()).unwrap();
                let (status, _) = a.event(e, |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<I>>(&self, c: &Context, b: &mut B) {
        for child in self.children.iter() {
            child.draw(c, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            &mut self.running[sprite_id].remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<commit_msg>Upgrade to latest piston-ai_behavior<commit_after>
use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id.clone()).unwrap();
                let (status, _) = a.event(e, &mut |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<I>>(&self, c: &Context, b: &mut B) {
        for child in self.children.iter() {
            child.draw(c, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = &mut self.running[sprite_id];
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            &mut self.running[sprite_id].remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use device::serial::COM1;
use event;
use scheme::*;
use sync::WaitQueue;
use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use syscall::scheme::Scheme;

pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;

/// Input queue
static INPUT: Once<WaitQueue<u8>> = Once::new();

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

static HANDLES: Once<RwLock<BTreeMap<usize, usize>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, usize>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn debug_input(b: u8) {
    INPUT.call_once(init_input).send(b);
    for (id, _flags) in handles().iter() {
        event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct DebugScheme;

impl DebugScheme {
    pub fn new(scheme_id: SchemeId) -> DebugScheme {
        DEBUG_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        DebugScheme
    }
}

impl Scheme for DebugScheme {
    fn open(&self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, flags & ! O_ACCMODE);

        Ok(id)
    }

    fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> {
        if ! buf.is_empty() {
            return Err(Error::new(EINVAL));
        }

        let flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let new_id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(new_id, flags);

        Ok(new_id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(INPUT.call_once(init_input).receive_into(buf, flags & O_NONBLOCK != O_NONBLOCK))
    }

    /// Write the `buffer` to the `file`
    ///
    /// Returns the number of bytes written
    fn write(&self, id: usize, buffer: &[u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut com = COM1.lock();
        for &byte in buffer.iter() {
            com.send(byte);
        }

        Ok(buffer.len())
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(flags) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(*flags),
                F_SETFL => {
                    *flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: usize) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"debug:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _flags = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<commit_msg>Debug scheme will return correct event id<commit_after>use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use device::serial::COM1;
use event;
use scheme::*;
use sync::WaitQueue;
use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use syscall::scheme::Scheme;

pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;

/// Input queue
static INPUT: Once<WaitQueue<u8>> = Once::new();

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

static HANDLES: Once<RwLock<BTreeMap<usize, usize>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, usize>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn debug_input(b: u8) {
    INPUT.call_once(init_input).send(b);
    for (id, _flags) in handles().iter() {
        event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct DebugScheme;

impl DebugScheme {
    pub fn new(scheme_id: SchemeId) -> DebugScheme {
        DEBUG_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        DebugScheme
    }
}

impl Scheme for DebugScheme {
    fn open(&self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, flags & ! O_ACCMODE);

        Ok(id)
    }

    fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> {
        if ! buf.is_empty() {
            return Err(Error::new(EINVAL));
        }

        let flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let new_id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(new_id, flags);

        Ok(new_id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(INPUT.call_once(init_input).receive_into(buf, flags & O_NONBLOCK != O_NONBLOCK))
    }

    /// Write the `buffer` to the `file`
    ///
    /// Returns the number of bytes written
    fn write(&self, id: usize, buffer: &[u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut com = COM1.lock();
        for &byte in buffer.iter() {
            com.send(byte);
        }

        Ok(buffer.len())
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(flags) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(*flags),
                F_SETFL => {
                    *flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: usize) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(id)
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"debug:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _flags = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<|endoftext|>


<commit_before>use crate::colour::Colour;
use crate::graph::{Graph, Position};
use crate::grid::Grid;

pub enum GameState {
    Solving,
    Solved,
}

pub struct Game {
    pub state: GameState,
    pub graph: Graph,
}

const top_left_cell: Position = Position{column: 0_usize, row: 0_usize};

impl Game {
    pub fn create(size: usize) -> Self {
        let grid = Grid::generate(size);
        let graph = Graph::create(&grid);
        Self {
            state: GameState::Solving,
            graph,
        }
    }

    pub fn fill_component_of_top_left_cell_with(&mut self, colour: Colour) {
        self.graph.change_colour_of_component_at(&top_left_cell, colour);
    }
}
<commit_msg>Use SHOUTING_CASE for top-level constant<commit_after>use crate::colour::Colour;
use crate::graph::{Graph, Position};
use crate::grid::Grid;

pub enum GameState {
    Solving,
    Solved,
}

pub struct Game {
    pub state: GameState,
    pub graph: Graph,
}

const TOP_LEFT_CELL: Position = Position{column: 0_usize, row: 0_usize};

impl Game {
    pub fn create(size: usize) -> Self {
        let grid = Grid::generate(size);
        let graph = Graph::create(&grid);
        Self {
            state: GameState::Solving,
            graph,
        }
    }

    pub fn fill_component_of_top_left_cell_with(&mut self, colour: Colour) {
        self.graph.change_colour_of_component_at(&TOP_LEFT_CELL, colour);
    }
}
<|endoftext|>


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

use common::*;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};
use std::collections::{HashMap, HashSet, VecDeque};

pub struct Game
{
    pub grid: Vec<Vec<Option<u64>>>,
    pub tokens: HashSet<Point>,
    pub turns_left: u64,
    pub rng: StdRng,
    pub gen_col: Range<usize>,
    pub gen_row: Range<usize>,
    pub game_id: u64,
    pub players: HashMap<u64, Player>,
    pub moved: HashMap<u64, bool>,
}

impl Game
{
    pub fn new(players: HashMap<u64, Player>, total_turns: u64, game_id: u64) -> Game
    {
        let mut players = players;
        let num_players = players.len();
        let rows = 8 + num_players / 2;
        let cols = rows * 2 + 1;
        let grid: Vec<Vec<Option<u64>>> = vec![vec![None; cols]; rows];
        let mut rng = StdRng::new().unwrap();
        let gen_row = Range::new(0, rows);
        let gen_col = Range::new(0, cols);
        let mut moved: HashMap<u64, bool> = Default::default();
        for player in players.values_mut()
        {
            player.position = Point {
                x: gen_col.ind_sample(&mut rng),
                y: gen_row.ind_sample(&mut rng),
            };
            moved.insert(player.id, false);
        }
        Game {
            grid: grid,
            tokens: Default::default(),
            turns_left: total_turns,
            rng: rng,
            gen_col: gen_col,
            gen_row: gen_row,
            game_id: game_id,
            players: players,
            moved: moved,
        }
    }

    pub fn finished(&self) -> bool
    {
        self.turns_left == 0
    }

    pub fn tick(&mut self)
    {
        for player in self.players.values()
        {
            self.grid[player.position.y][player.position.x] = Some(player.id);
        }
        let mut visited: HashSet<Point> = Default::default();
        let cols = self.grid[0].len();
        let rows = self.grid.len();
        for y in 0..rows
        {
            for x in 0..cols
            {
                if visited.contains(&Point { x: x, y: y }) || self.grid[y][x].is_some()
                {
                    continue;
                }
                let mut to_fill: HashSet<Point> = Default::default();
                let mut colors: HashSet<u64> = Default::default();
                let mut queue: VecDeque<Point> = Default::default();
                let mut valid = true;
                queue.push_back(Point { x: x, y: y });
                while !queue.is_empty()
                {
                    let p = queue.pop_front().unwrap();
                    if let Some(color) = self.grid[p.y][p.x]
                    {
                        colors.insert(color);
                        continue;
                    }
                    if to_fill.contains(&p)
                    {
                        continue;
                    }
                    to_fill.insert(p.clone());
                    visited.insert(p.clone());
                    if p.x + 1 >= cols || (p.x as i64) - 1 < 0 || p.y + 1 >= rows || (p.y as i64) - 1 < 0
                    {
                        valid = false;
                        break;
                    }
                    queue.push_back(Point {
                                        x: p.x + 1,
                                        y: p.y,
                                    });
                    queue.push_back(Point {
                                        x: p.x - 1,
                                        y: p.y,
                                    });
                    queue.push_back(Point {
                                        x: p.x,
                                        y: p.y + 1,
                                    });
                    queue.push_back(Point {
                                        x: p.x,
                                        y: p.y - 1,
                                    });
                }
                if valid && colors.len() == 1
                {
                    let color = colors.drain().last().unwrap();
                    for p in to_fill.drain()
                    {
                        self.grid[p.y][p.x] = Some(color);
                    }
                }
            }
        }
        for player in self.players.values_mut()
        {
            *self.moved.get_mut(&player.id).unwrap() = false;
            if self.tokens.contains(&player.position)
            {
                let mut count: u64 = 0;
                self.tokens.remove(&player.position);
                for y in 0..rows
                {
                    for x in 0..cols
                    {
                        match self.grid[y][x]
                        {
                            Some(c) if c == player.id =>
                            {
                                self.grid[y][x] = None;
                                count += 1;
                            }
                            _ => continue,
                        }
                    }
                }
                player.points += count;
            }
        }
        self.turns_left -= 1;
        let mut count = 0;
        let mut cap = 0.025 * (self.players.len() as f64).log2();
        if cap > 0.5
        {
            cap = 0.5;
        }
        while self.rng.next_f64() < cap
        {
            count += 1;
        }
        for _ in 0..count
        {
            self.tokens.insert(Point {
                                   x: self.gen_col.ind_sample(&mut self.rng),
                                   y: self.gen_row.ind_sample(&mut self.rng),
                               });
        }
    }

    pub fn action(&mut self, id: u64, command: ClientCommand) -> Result<(), String>
    {
        let ok = match self.moved.get(&id)
        {
            Some(x) => !x,
            None => false,
        };
        if !ok
        {
            return Err(String::from("Already moved"));
        }
        *self.moved.get_mut(&id).unwrap() = true;
        let mut positions: HashSet<Point> = Default::default();
        for pos in self.players.values().map(|p| p.position.clone())
        {
            positions.insert(pos);
        }
        let player = self.players.get_mut(&id).unwrap();
        let cols = self.grid[0].len();
        let rows = self.grid.len();
        match command
        {
            ClientCommand::Nothing => Ok(()),
            ClientCommand::Move(direction) =>
            {
                match direction
                {
                    Direction::Up if player.position.y + 1 < rows &&
                                     !positions.contains(&Point {
                                                              x: player.position.x,
                                                              y: player.position.y + 1,
                                                          }) =>
                    {
                        player.position.y += 1;
                        Ok(())
                    }
                    Direction::Down if (player.position.y as i64) - 1 >= 0 &&
                                       !positions.contains(&Point {
                                                                x: player.position.x,
                                                                y: player.position.y - 1,
                                                            }) =>
                    {
                        player.position.y -= 1;
                        Ok(())
                    }
                    Direction::Right if player.position.x + 1 < cols &&
                                        !positions.contains(&Point {
                                                                 x: player.position.x + 1,
                                                                 y: player.position.y,
                                                             }) =>
                    {
                        player.position.x += 1;
                        Ok(())
                    }
                    Direction::Left if (player.position.x as i64) - 1 >= 0 &&
                                       !positions.contains(&Point {
                                                                x: player.position.x - 1,
                                                                y: player.position.y,
                                                            }) =>
                    {
                        player.position.x -= 1;
                        Ok(())
                    }
                    _ =>
                    {
                        *self.moved.get_mut(&id).unwrap() = false;
                        Err(String::from("Moved out of grid or in a cell already taken"))
                    }
                }
            }

        }
    }
}
<commit_msg>Change y-axis direction to match viewer<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2017 - Dario Ostuni <dario.ostuni@gmail.com>
 *
 */

use common::*;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};
use std::collections::{HashMap, HashSet, VecDeque};

pub struct Game
{
    pub grid: Vec<Vec<Option<u64>>>,
    pub tokens: HashSet<Point>,
    pub turns_left: u64,
    pub rng: StdRng,
    pub gen_col: Range<usize>,
    pub gen_row: Range<usize>,
    pub game_id: u64,
    pub players: HashMap<u64, Player>,
    pub moved: HashMap<u64, bool>,
}

impl Game
{
    pub fn new(players: HashMap<u64, Player>, total_turns: u64, game_id: u64) -> Game
    {
        let mut players = players;
        let num_players = players.len();
        let rows = 8 + num_players / 2;
        let cols = rows * 2 + 1;
        let grid: Vec<Vec<Option<u64>>> = vec![vec![None; cols]; rows];
        let mut rng = StdRng::new().unwrap();
        let gen_row = Range::new(0, rows);
        let gen_col = Range::new(0, cols);
        let mut moved: HashMap<u64, bool> = Default::default();
        for player in players.values_mut()
        {
            player.position = Point {
                x: gen_col.ind_sample(&mut rng),
                y: gen_row.ind_sample(&mut rng),
            };
            moved.insert(player.id, false);
        }
        Game {
            grid: grid,
            tokens: Default::default(),
            turns_left: total_turns,
            rng: rng,
            gen_col: gen_col,
            gen_row: gen_row,
            game_id: game_id,
            players: players,
            moved: moved,
        }
    }

    pub fn finished(&self) -> bool
    {
        self.turns_left == 0
    }

    pub fn tick(&mut self)
    {
        for player in self.players.values()
        {
            self.grid[player.position.y][player.position.x] = Some(player.id);
        }
        let mut visited: HashSet<Point> = Default::default();
        let cols = self.grid[0].len();
        let rows = self.grid.len();
        for y in 0..rows
        {
            for x in 0..cols
            {
                if visited.contains(&Point { x: x, y: y }) || self.grid[y][x].is_some()
                {
                    continue;
                }
                let mut to_fill: HashSet<Point> = Default::default();
                let mut colors: HashSet<u64> = Default::default();
                let mut queue: VecDeque<Point> = Default::default();
                let mut valid = true;
                queue.push_back(Point { x: x, y: y });
                while !queue.is_empty()
                {
                    let p = queue.pop_front().unwrap();
                    if let Some(color) = self.grid[p.y][p.x]
                    {
                        colors.insert(color);
                        continue;
                    }
                    if to_fill.contains(&p)
                    {
                        continue;
                    }
                    to_fill.insert(p.clone());
                    visited.insert(p.clone());
                    if p.x + 1 >= cols || (p.x as i64) - 1 < 0 || p.y + 1 >= rows || (p.y as i64) - 1 < 0
                    {
                        valid = false;
                        break;
                    }
                    queue.push_back(Point {
                                        x: p.x + 1,
                                        y: p.y,
                                    });
                    queue.push_back(Point {
                                        x: p.x - 1,
                                        y: p.y,
                                    });
                    queue.push_back(Point {
                                        x: p.x,
                                        y: p.y + 1,
                                    });
                    queue.push_back(Point {
                                        x: p.x,
                                        y: p.y - 1,
                                    });
                }
                if valid && colors.len() == 1
                {
                    let color = colors.drain().last().unwrap();
                    for p in to_fill.drain()
                    {
                        self.grid[p.y][p.x] = Some(color);
                    }
                }
            }
        }
        for player in self.players.values_mut()
        {
            *self.moved.get_mut(&player.id).unwrap() = false;
            if self.tokens.contains(&player.position)
            {
                let mut count: u64 = 0;
                self.tokens.remove(&player.position);
                for y in 0..rows
                {
                    for x in 0..cols
                    {
                        match self.grid[y][x]
                        {
                            Some(c) if c == player.id =>
                            {
                                self.grid[y][x] = None;
                                count += 1;
                            }
                            _ => continue,
                        }
                    }
                }
                player.points += count;
            }
        }
        self.turns_left -= 1;
        let mut count = 0;
        let mut cap = 0.025 * (self.players.len() as f64).log2();
        if cap > 0.5
        {
            cap = 0.5;
        }
        while self.rng.next_f64() < cap
        {
            count += 1;
        }
        for _ in 0..count
        {
            self.tokens.insert(Point {
                                   x: self.gen_col.ind_sample(&mut self.rng),
                                   y: self.gen_row.ind_sample(&mut self.rng),
                               });
        }
    }

    pub fn action(&mut self, id: u64, command: ClientCommand) -> Result<(), String>
    {
        let ok = match self.moved.get(&id)
        {
            Some(x) => !x,
            None => false,
        };
        if !ok
        {
            return Err(String::from("Already moved"));
        }
        *self.moved.get_mut(&id).unwrap() = true;
        let mut positions: HashSet<Point> = Default::default();
        for pos in self.players.values().map(|p| p.position.clone())
        {
            positions.insert(pos);
        }
        let player = self.players.get_mut(&id).unwrap();
        let cols = self.grid[0].len();
        let rows = self.grid.len();
        match command
        {
            ClientCommand::Nothing => Ok(()),
            ClientCommand::Move(direction) =>
            {
                match direction
                {
                    Direction::Down if player.position.y + 1 < rows &&
                                     !positions.contains(&Point {
                                                              x: player.position.x,
                                                              y: player.position.y + 1,
                                                          }) =>
                    {
                        player.position.y += 1;
                        Ok(())
                    }
                    Direction::Up if (player.position.y as i64) - 1 >= 0 &&
                                       !positions.contains(&Point {
                                                                x: player.position.x,
                                                                y: player.position.y - 1,
                                                            }) =>
                    {
                        player.position.y -= 1;
                        Ok(())
                    }
                    Direction::Right if player.position.x + 1 < cols &&
                                        !positions.contains(&Point {
                                                                 x: player.position.x + 1,
                                                                 y: player.position.y,
                                                             }) =>
                    {
                        player.position.x += 1;
                        Ok(())
                    }
                    Direction::Left if (player.position.x as i64) - 1 >= 0 &&
                                       !positions.contains(&Point {
                                                                x: player.position.x - 1,
                                                                y: player.position.y,
                                                            }) =>
                    {
                        player.position.x -= 1;
                        Ok(())
                    }
                    _ =>
                    {
                        *self.moved.get_mut(&id).unwrap() = false;
                        Err(String::from("Moved out of grid or in a cell already taken"))
                    }
                }
            }

        }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate cgmath;
extern crate common;
#[macro_use]
extern crate log;
extern crate noise;
extern crate num;
extern crate stopwatch;

mod generate;
mod heightmap;
mod raycast;

pub mod voxel;
pub mod voxel_tree;

pub use noise::Seed;

use std::collections::hash_map::HashMap;
use std::iter::range_inclusive;
use std::sync::Mutex;
use stopwatch::TimerSet;

use common::block_position::BlockPosition;
use common::entity::EntityId;
use common::id_allocator::IdAllocator;
use common::lod::LODIndex;
use common::terrain_block;
use common::terrain_block::TerrainBlock;

use heightmap::HeightMap;
use voxel::{Voxel, Fracu8, Fraci8};
use voxel_tree::VoxelTree;

pub const AMPLITUDE: f64 = 64.0;
pub const FREQUENCY: f64 = 1.0 / 64.0;
pub const PERSISTENCE: f64 = 1.0 / 16.0;
pub const LACUNARITY: f64 = 8.0;
pub const OCTAVES: usize = 2;

pub struct MipMesh {
  pub lods: Vec<Option<TerrainBlock>>,
}

impl MipMesh {
  pub fn get_mut<'a>(&'a mut self, i: usize) -> &'a mut Option<TerrainBlock> {
    for _ in range_inclusive(self.lods.len(), i) {
      self.lods.push(None);
    }
    self.lods.get_mut(i).unwrap()
  }
}

pub struct MipMeshMap(pub HashMap<BlockPosition, MipMesh>);

impl MipMeshMap {
  pub fn new() -> MipMeshMap {
    MipMeshMap(HashMap::new())
  }

  pub fn get<'a>(&'a mut self, position: &BlockPosition) -> Option<&'a MipMesh> {
    self.0.get(position)
  }

  pub fn get_mut<'a>(&'a mut self, position: &BlockPosition) -> &'a mut MipMesh {
    self.0
      .entry(*position)
      .or_insert_with(|| {
        MipMesh {
          lods: Vec::new(),
        }
      })
  }
}

/// This struct contains and lazily generates the world's terrain.
pub struct Terrain {
  pub heightmap: HeightMap,
  // all the blocks that have ever been created.
  pub all_blocks: MipMeshMap,
  pub voxels: VoxelTree,
}

impl Terrain {
  pub fn new(terrain_seed: Seed) -> Terrain {
    Terrain {
      heightmap: HeightMap::new(terrain_seed, OCTAVES, FREQUENCY, PERSISTENCE, LACUNARITY),
      all_blocks: MipMeshMap::new(),
      voxels: VoxelTree::new(),
    }
  }

  // TODO: Allow this to be performed in such a way that self is only briefly locked.
  pub fn load<'a>(
    &'a mut self,
    timers: &TimerSet,
    id_allocator: &Mutex<IdAllocator<EntityId>>,
    position: &BlockPosition,
    lod_index: LODIndex,
  ) -> &'a TerrainBlock
  {
    let mip_mesh = self.all_blocks.get_mut(position);
    let mesh = mip_mesh.get_mut(lod_index.0 as usize);
    if mesh.is_none() {
      *mesh = Some(
        generate::generate_block(
          timers,
          id_allocator,
          &self.heightmap,
          &mut self.voxels,
          position,
          lod_index,
        )
      );
    }
    mesh.as_ref().unwrap()
  }

  pub fn remove_voxel<F>(
    &mut self,
    timers: &TimerSet,
    id_allocator: &Mutex<IdAllocator<EntityId>>,
    bounds: &voxel::Bounds,
    mut block_changed: F,
  )
    where F: FnMut(&TerrainBlock, &BlockPosition, LODIndex),
  {
    match self.voxels.get_mut(bounds) {
      None => {
        return;
      },
      Some(voxel) => {
        *voxel = Voxel::Volume(false);
      },
    }

    // Ensure all the neighbors are populated.
    // TODO: Search for all these voxels in a single tree search.
    for &dx in [-1, 0, 1].iter() {
    for &dy in [-1, 0, 1].iter() {
    for &dz in [-1, 0, 1].iter() {
      let (x, y, z) = (bounds.x + dx, bounds.y + dy, bounds.z + dz);
      let bounds = voxel::Bounds::new(x, y, z, bounds.lg_size);
      let voxel = self.voxels.get_mut_or_create(&bounds);
      match voxel {
        &mut voxel_tree::TreeBody::Leaf(_) => {},
        _ => {
          *voxel =
            voxel_tree::TreeBody::Leaf(generate::generate_voxel(
              timers,
              &self.heightmap,
              &bounds,
            ));
        },
      }
      match voxel {
        &mut voxel_tree::TreeBody::Leaf(Voxel::Volume(true)) => {
          let half = Fracu8::of(0x80);
          let surface =
            voxel::SurfaceVoxel {
              inner_vertex: voxel::Vertex { x: half, y: half, z: half },
              // TODO: Make real normals.
              normal: voxel::Normal { x: Fraci8::of(0), y: Fraci8::of(0x7F), z: Fraci8::of(0) },
              corner_inside_surface: true,
            };
          *voxel = voxel_tree::TreeBody::Leaf(Voxel::Surface(surface));
        },
        _ => {},
      }
    }}}

    // Remove all the corners.
    // TODO: Search for all these voxels in a single tree search.
    for &dx in [0, 1].iter() {
    for &dy in [0, 1].iter() {
    for &dz in [0, 1].iter() {
      let (x, y, z) = (bounds.x + dx, bounds.y + dy, bounds.z + dz);
      let bounds = voxel::Bounds::new(x, y, z, bounds.lg_size);
      let voxel = self.voxels.get_mut(&bounds);
      match voxel {
        Some(&mut Voxel::Surface(ref mut voxel)) => {
          voxel.corner_inside_surface = false;
        },
        _ => {},
      }
    }}}

    // TODO: Consider regenerating the TerrainBlocks for the adjacent voxels too.

    // lg(number of voxels in a block)
    let lg_scale = terrain_block::LG_WIDTH - bounds.lg_size;
    let position =
      BlockPosition::new(bounds.x >> lg_scale, bounds.y >> lg_scale, bounds.z >> lg_scale);

    let lod_index =
      terrain_block::LG_SAMPLE_SIZE.iter()
      .position(|&x| x == bounds.lg_size)
      .unwrap()
    ;
    let lod_index = LODIndex(lod_index as u32);

    let mip_mesh = self.all_blocks.get_mut(&position);
    let mesh = mip_mesh.get_mut(lod_index.0 as usize);
    *mesh = Some(
      generate::generate_block(
        timers,
        id_allocator,
        &self.heightmap,
        &mut self.voxels,
        &position,
        lod_index,
      )
    );

    block_changed(mesh.as_ref().unwrap(), &position, lod_index);
  }
}
<commit_msg>Regenerate neighboring TerrainBlocks as necessary<commit_after>#![feature(core)]

extern crate cgmath;
extern crate common;
#[macro_use]
extern crate log;
extern crate noise;
extern crate num;
extern crate stopwatch;

mod generate;
mod heightmap;
mod raycast;

pub mod voxel;
pub mod voxel_tree;

pub use noise::Seed;

use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::iter::range_inclusive;
use std::sync::Mutex;
use stopwatch::TimerSet;

use common::block_position::BlockPosition;
use common::entity::EntityId;
use common::id_allocator::IdAllocator;
use common::lod::LODIndex;
use common::terrain_block;
use common::terrain_block::TerrainBlock;

use heightmap::HeightMap;
use voxel::{Voxel, Fracu8, Fraci8};
use voxel_tree::VoxelTree;

pub const AMPLITUDE: f64 = 64.0;
pub const FREQUENCY: f64 = 1.0 / 64.0;
pub const PERSISTENCE: f64 = 1.0 / 16.0;
pub const LACUNARITY: f64 = 8.0;
pub const OCTAVES: usize = 2;

pub struct MipMesh {
  pub lods: Vec<Option<TerrainBlock>>,
}

impl MipMesh {
  pub fn get_mut<'a>(&'a mut self, i: usize) -> &'a mut Option<TerrainBlock> {
    for _ in range_inclusive(self.lods.len(), i) {
      self.lods.push(None);
    }
    self.lods.get_mut(i).unwrap()
  }
}

pub struct MipMeshMap(pub HashMap<BlockPosition, MipMesh>);

impl MipMeshMap {
  pub fn new() -> MipMeshMap {
    MipMeshMap(HashMap::new())
  }

  pub fn get<'a>(&'a mut self, position: &BlockPosition) -> Option<&'a MipMesh> {
    self.0.get(position)
  }

  pub fn get_mut<'a>(&'a mut self, position: &BlockPosition) -> &'a mut MipMesh {
    self.0
      .entry(*position)
      .or_insert_with(|| {
        MipMesh {
          lods: Vec::new(),
        }
      })
  }
}

/// This struct contains and lazily generates the world's terrain.
pub struct Terrain {
  pub heightmap: HeightMap,
  // all the blocks that have ever been created.
  pub all_blocks: MipMeshMap,
  pub voxels: VoxelTree,
}

impl Terrain {
  pub fn new(terrain_seed: Seed) -> Terrain {
    Terrain {
      heightmap: HeightMap::new(terrain_seed, OCTAVES, FREQUENCY, PERSISTENCE, LACUNARITY),
      all_blocks: MipMeshMap::new(),
      voxels: VoxelTree::new(),
    }
  }

  // TODO: Allow this to be performed in such a way that self is only briefly locked.
  pub fn load<'a>(
    &'a mut self,
    timers: &TimerSet,
    id_allocator: &Mutex<IdAllocator<EntityId>>,
    position: &BlockPosition,
    lod_index: LODIndex,
  ) -> &'a TerrainBlock
  {
    let mip_mesh = self.all_blocks.get_mut(position);
    let mesh = mip_mesh.get_mut(lod_index.0 as usize);
    if mesh.is_none() {
      *mesh = Some(
        generate::generate_block(
          timers,
          id_allocator,
          &self.heightmap,
          &mut self.voxels,
          position,
          lod_index,
        )
      );
    }
    mesh.as_ref().unwrap()
  }

  pub fn remove_voxel<F>(
    &mut self,
    timers: &TimerSet,
    id_allocator: &Mutex<IdAllocator<EntityId>>,
    bounds: &voxel::Bounds,
    mut block_changed: F,
  )
    where F: FnMut(&TerrainBlock, &BlockPosition, LODIndex),
  {
   debug!("remove {:?}", bounds);

    match self.voxels.get_mut(bounds) {
      None => {
        return;
      },
      Some(voxel) => {
        *voxel = Voxel::Volume(false);
      },
    }

    // Ensure all the neighbors are populated.
    // TODO: Search for all these voxels in a single tree search.
    for &dx in [-1, 0, 1].iter() {
    for &dy in [-1, 0, 1].iter() {
    for &dz in [-1, 0, 1].iter() {
      let (x, y, z) = (bounds.x + dx, bounds.y + dy, bounds.z + dz);
      debug!("adjacent {:?} {:?} {:?}", x, y, z);

      let bounds = voxel::Bounds::new(x, y, z, bounds.lg_size);
      let voxel = self.voxels.get_mut_or_create(&bounds);
      debug!("voxel {:?}", *voxel);

      match voxel {
        &mut voxel_tree::TreeBody::Leaf(_) => {},
        _ => {
          *voxel =
            voxel_tree::TreeBody::Leaf(generate::generate_voxel(
              timers,
              &self.heightmap,
              &bounds,
            ));

          debug!("voxel changing to {:?}", *voxel);
        },
      }
      match voxel {
        &mut voxel_tree::TreeBody::Leaf(Voxel::Volume(true)) => {
          let half = Fracu8::of(0x80);
          let surface =
            voxel::SurfaceVoxel {
              inner_vertex: voxel::Vertex { x: half, y: half, z: half },
              // TODO: Make real normals.
              normal: voxel::Normal { x: Fraci8::of(0), y: Fraci8::of(0x7F), z: Fraci8::of(0) },
              corner_inside_surface: true,
            };
          *voxel = voxel_tree::TreeBody::Leaf(Voxel::Surface(surface));

          debug!("voxel detailing to {:?}", *voxel);
        },
        _ => {},
      }
    }}}

    // Remove all the corners.
    // TODO: Search for all these voxels in a single tree search.
    for &dx in [0, 1].iter() {
    for &dy in [0, 1].iter() {
    for &dz in [0, 1].iter() {
      let (x, y, z) = (bounds.x + dx, bounds.y + dy, bounds.z + dz);
      debug!("corner {:?} {:?} {:?}", x, y, z);

      let bounds = voxel::Bounds::new(x, y, z, bounds.lg_size);
      let voxel = self.voxels.get_mut(&bounds);

      debug!("voxel {:?}", voxel.as_ref().map(|&&mut v| v));
      match voxel {
        Some(&mut Voxel::Surface(ref mut voxel)) => {
          voxel.corner_inside_surface = false;
        },
        _ => {},
      }
    }}}

    // TODO: Consider regenerating the TerrainBlocks for the adjacent voxels too.

    // lg(number of voxels in a block)
    let lg_scale = terrain_block::LG_WIDTH - bounds.lg_size;

    let mut positions = HashSet::new();
    for &dx in [-1, 0, 1].iter() {
    for &dy in [-1, 0, 1].iter() {
    for &dz in [-1, 0, 1].iter() {
      let (x, y, z) = (bounds.x + dx, bounds.y + dy, bounds.z + dz);
      let bounds = voxel::Bounds::new(x, y, z, bounds.lg_size);
      let position =
        BlockPosition::new(bounds.x >> lg_scale, bounds.y >> lg_scale, bounds.z >> lg_scale);
      positions.insert(position);
    }}}

    for position in positions.into_iter() {
      let lod_index =
        terrain_block::LG_SAMPLE_SIZE.iter()
        .position(|&x| x == bounds.lg_size)
        .unwrap()
      ;
      let lod_index = LODIndex(lod_index as u32);

      let mip_mesh = self.all_blocks.get_mut(&position);
      let mesh = mip_mesh.get_mut(lod_index.0 as usize);
      *mesh = Some(
        generate::generate_block(
          timers,
          id_allocator,
          &self.heightmap,
          &mut self.voxels,
          &position,
          lod_index,
        )
      );

      block_changed(mesh.as_ref().unwrap(), &position, lod_index);
    }
  }
}
<|endoftext|>