diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/block.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/block.rs
index fb8707a25cecb72f3d5b31daab0f67737d0138f1..af71b805bd4c91a2fd104723bbc5f3c654d90e2f 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/block.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/block.rs
@@ -86,12 +86,14 @@ impl<T: ReadableBlockContainer> Block<T> {
     }
 
     /// Returns the magic number in a HEADER block.
+    #[cfg(test)]
     pub fn header_magic(&self) -> Result<u32, Error> {
         self.check_type(BlockType::Header)?;
         Ok(self.read_header().header_magic())
     }
 
     /// Returns the version of a HEADER block.
+    #[cfg(test)]
     pub fn header_version(&self) -> Result<u32, Error> {
         self.check_type(BlockType::Header)?;
         Ok(self.read_header().header_version())
@@ -122,6 +124,7 @@ impl<T: ReadableBlockContainer> Block<T> {
     }
 
     /// Get the total length of the PROPERTY block.
+    #[cfg(test)]
     pub fn property_total_length(&self) -> Result<u32, Error> {
         self.check_type(BlockType::PropertyValue)?;
         Ok(self.read_payload().property_total_length())
@@ -140,6 +143,7 @@ impl<T: ReadableBlockContainer> Block<T> {
     }
 
     /// Returns the payload bytes value of an EXTENT block.
+    #[cfg(test)]
     pub fn extent_contents(&self) -> Result<Vec<u8>, Error> {
         self.check_type(BlockType::Extent)?;
         let length = utils::payload_size_for_order(self.order());
@@ -173,12 +177,14 @@ impl<T: ReadableBlockContainer> Block<T> {
     }
 
     /// Get the length of the name of a NAME block
+    #[cfg(test)]
     pub fn name_length(&self) -> Result<usize, Error> {
         self.check_type(BlockType::Name)?;
         Ok(self.read_header().name_length().to_usize().unwrap())
     }
 
     /// Returns the contents of a NAME block.
+    #[cfg(test)]
     pub fn name_contents(&self) -> Result<String, Error> {
         self.check_type(BlockType::Name)?;
         let length = self.name_length()?;
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/block_type.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/block_type.rs
index f930bce23c8344af056ef65a6fea0d789a7d7428..873c0a0a3dc6b8cda77099de7de394f76b87b52b 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/block_type.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/block_type.rs
@@ -75,6 +75,7 @@ impl BlockType {
         }
     }
 
+    #[cfg(test)]
     pub fn all() -> [BlockType; 11] {
         [
             BlockType::Free,
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/heap.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/heap.rs
index 2a2ba2113bb2105d896fd0225801d27253eed060..edaa7af2585fb02a0178b52bb5a96f4d0a90bc10 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/heap.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/heap.rs
@@ -93,7 +93,7 @@ impl Heap {
     }
 
     /// The bytes in this heap.
-    #[allow(dead_code)] // Used in testing.
+    #[cfg(test)]
     pub(in crate::vmo) fn bytes(&self) -> Vec<u8> {
         let mut result = vec![0u8; self.current_size_bytes];
         self.mapping.read(&mut result[..]);
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/inspector.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/inspector.rs
deleted file mode 100644
index 8e7f26a1baffd8136e1d2797438cdbbb980ab41c..0000000000000000000000000000000000000000
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/inspector.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use failure::{format_err, Error};
-use mapped_vmo::Mapping;
-use parking_lot::Mutex;
-use std::rc::Rc;
-use std::sync::Arc;
-
-use crate::vmo::constants;
-use crate::vmo::heap::Heap;
-use crate::vmo::state::State;
-use crate::vmo::types::Node;
-
-/// Root of the Inspect API
-pub struct Inspector {
-    /// The root node.
-    root_node: Node,
-}
-
-impl Inspector {
-    /// Create a new Inspect VMO object with the given maximum size.
-    pub fn new(max_size: usize, name: &str) -> Result<Self, Error> {
-        let (mapping, _) = Mapping::allocate(max_size)
-            .map_err(|e| format_err!("failed to allocate vmo zx status={}", e))?;
-        let heap = Heap::new(Rc::new(mapping))?;
-        let state = State::create(heap)?;
-        let root_node =
-            Node::allocate(Arc::new(Mutex::new(state)), name, constants::ROOT_PARENT_INDEX)?;
-        Ok(Inspector { root_node })
-    }
-
-    /// Create the root of the VMO object with the given |name|.
-    pub fn root(&self) -> &Node {
-        &self.root_node
-    }
-}
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/mod.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/mod.rs
index eb069321a849f5a953570311f6d6506bcb5de96a..21f06b05efe027b8c02e7cd84799e080999219ed 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/mod.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/mod.rs
@@ -2,13 +2,405 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use failure::{format_err, Error};
+use mapped_vmo::Mapping;
+use num_traits::ToPrimitive;
+use parking_lot::Mutex;
+use paste;
+use std::marker::PhantomData;
+use std::rc::Rc;
+use std::sync::Arc;
+
+use crate::vmo::heap::Heap;
+use crate::vmo::state::State;
+
 mod bitfields;
 mod block;
 mod block_type;
 mod constants;
 mod heap;
-pub mod inspector;
-pub mod reader;
+mod reader;
 mod state;
-pub mod types;
 mod utils;
+
+/// Root of the Inspect API
+pub struct Inspector {
+    /// The root node.
+    root_node: Node,
+}
+
+/// Allowed formats for a Metric data type (uint, int, double)
+pub trait MetricFormat {}
+impl MetricFormat for u64 {}
+impl MetricFormat for i64 {}
+impl MetricFormat for f64 {}
+
+/// Provides functions required to implement formats for a property.
+pub trait PropertyFormat {
+    fn bytes(&self) -> &[u8];
+    fn flag(&self) -> u8;
+    fn length_in_bytes(&self) -> u32;
+}
+
+/// Inspect API Node data type.
+pub struct Node {
+    /// Index of the block in the VMO.
+    block_index: u32,
+
+    /// Reference to the VMO heap.
+    state: Arc<Mutex<State>>,
+}
+
+/// Inspect API Metric data type.
+pub struct Metric<T: MetricFormat> {
+    /// Index of the block in the VMO.
+    block_index: u32,
+
+    /// Reference to the VMO heap.
+    state: Arc<Mutex<State>>,
+    phantom: PhantomData<T>,
+}
+
+/// Inspect API Property data type.
+pub struct Property<T: PropertyFormat> {
+    /// Index of the block in the VMO.
+    block_index: u32,
+
+    /// Reference to the VMO heap.
+    state: Arc<Mutex<State>>,
+    phantom: PhantomData<T>,
+}
+
+/// Root API for inspect. Used to create the VMO and get the root node.
+impl Inspector {
+    /// Create a new Inspect VMO object with the given maximum size.
+    pub fn new(max_size: usize, name: &str) -> Result<Self, Error> {
+        let (mapping, _) = Mapping::allocate(max_size)
+            .map_err(|e| format_err!("failed to allocate vmo zx status={}", e))?;
+        let heap = Heap::new(Rc::new(mapping))?;
+        let state = State::create(heap)?;
+        let root_node =
+            Node::allocate(Arc::new(Mutex::new(state)), name, constants::ROOT_PARENT_INDEX)?;
+        Ok(Inspector { root_node })
+    }
+
+    /// Create the root of the VMO object with the given |name|.
+    pub fn root(&self) -> &Node {
+        &self.root_node
+    }
+}
+
+/// Implementation of property for a byte vector.
+impl PropertyFormat for &[u8] {
+    fn bytes(&self) -> &[u8] {
+        &self
+    }
+
+    fn flag(&self) -> u8 {
+        constants::PROPERTY_FLAG_BYTE_VECTOR
+    }
+
+    fn length_in_bytes(&self) -> u32 {
+        self.len().to_u32().unwrap()
+    }
+}
+
+/// Implementation of property for a string.
+impl PropertyFormat for &str {
+    fn bytes(&self) -> &[u8] {
+        self.as_bytes()
+    }
+
+    fn flag(&self) -> u8 {
+        constants::PROPERTY_FLAG_STRING
+    }
+
+    fn length_in_bytes(&self) -> u32 {
+        self.bytes().len().to_u32().unwrap()
+    }
+}
+
+/// Implementation of property for a string.
+impl PropertyFormat for String {
+    fn bytes(&self) -> &[u8] {
+        self.as_bytes()
+    }
+
+    fn flag(&self) -> u8 {
+        constants::PROPERTY_FLAG_STRING
+    }
+
+    fn length_in_bytes(&self) -> u32 {
+        self.bytes().len().to_u32().unwrap()
+    }
+}
+
+/// Utility for generating functions to create a metric.
+///   `name`: identifier for the name (example: double)
+///   `type`: the type of the metric (example: f64)
+macro_rules! create_metric_fn {
+    ($name:ident, $type:ident) => {
+        paste::item! {
+            pub fn [<create_ $name _metric>](&self, name: &str, value: $type)
+                -> Result<Metric<$type>, Error> {
+                let block = self.state.lock().[<create_ $name _metric>](
+                    name, value, self.block_index)?;
+                Ok(Metric::<$type> {state: self.state.clone(), block_index: block.index(), phantom: PhantomData})
+            }
+        }
+    };
+}
+
+impl Node {
+    /// Allocate a new NODE object. Called through Inspector.
+    pub(in crate::vmo) fn allocate(
+        state: Arc<Mutex<State>>,
+        name: &str,
+        parent_index: u32,
+    ) -> Result<Self, Error> {
+        let block = state.lock().create_node(name, parent_index)?;
+        Ok(Node { state: state.clone(), block_index: block.index() })
+    }
+
+    /// Add a child to this node.
+    pub fn create_child(&self, name: &str) -> Result<Node, Error> {
+        let block = self.state.lock().create_node(name, self.block_index)?;
+        Ok(Node { state: self.state.clone(), block_index: block.index() })
+    }
+
+    /// Add a metric to this node: create_int_metric, create_double_metric,
+    /// create_uint_metric.
+    create_metric_fn!(int, i64);
+    create_metric_fn!(uint, u64);
+    create_metric_fn!(double, f64);
+
+    /// Add a property to this node.
+    pub fn create_property<T: PropertyFormat>(
+        &self,
+        name: &str,
+        value: T,
+    ) -> Result<Property<T>, Error> {
+        let block = self.state.lock().create_property(name, value, self.block_index)?;
+        Ok(Property::<T> {
+            state: self.state.clone(),
+            block_index: block.index(),
+            phantom: PhantomData,
+        })
+    }
+}
+
+impl Drop for Node {
+    fn drop(&mut self) {
+        self.state
+            .lock()
+            .free_value(self.block_index)
+            .expect(&format!("Failed to free node index={}", self.block_index));
+    }
+}
+
+/// Utility for generating metric functions (example: set, add, subtract)
+///   `fn_name`: the name of the function to generate (example: set)
+///   `type`: the type of the argument of the function to generate (example: f64)
+///   `name`: the readble name of the type of the function (example: double)
+macro_rules! metric_fn {
+    ($fn_name:ident, $type:ident, $name:ident) => {
+        paste::item! {
+            pub fn $fn_name(&self, value: $type) -> Result<(), Error> {
+                self.state.lock().[<$fn_name _ $name _metric>](self.block_index, value)
+            }
+        }
+    };
+}
+
+/// Utility for generating a metric datatype impl
+///   `name`: the readble name of the type of the function (example: double)
+///   `type`: the type of the argument of the function to generate (example: f64)
+macro_rules! metric_impl {
+    ($name:ident, $type:ident) => {
+        impl Metric<$type> {
+            metric_fn!(set, $type, $name);
+            metric_fn!(add, $type, $name);
+            metric_fn!(subtract, $type, $name);
+        }
+    };
+}
+
+metric_impl!(int, i64);
+metric_impl!(uint, u64);
+metric_impl!(double, f64);
+
+impl<T: MetricFormat> Drop for Metric<T> {
+    fn drop(&mut self) {
+        self.state
+            .lock()
+            .free_value(self.block_index)
+            .expect(&format!("Failed to free metric index={}", self.block_index));
+    }
+}
+
+impl<T: PropertyFormat> Property<T> {
+    /// Set a property value.
+    pub fn set(&self, value: T) -> Result<(), Error> {
+        self.state.lock().set_property(self.block_index, value)
+    }
+}
+
+impl<T: PropertyFormat> Drop for Property<T> {
+    fn drop(&mut self) {
+        self.state
+            .lock()
+            .free_property(self.block_index)
+            .expect(&format!("Failed to free property index={}", self.block_index));
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::vmo::block_type::BlockType;
+    use crate::vmo::constants;
+    use crate::vmo::heap::Heap;
+    use mapped_vmo::Mapping;
+    use std::rc::Rc;
+
+    #[test]
+    fn node() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        assert_eq!(node_block.block_type(), BlockType::NodeValue);
+        assert_eq!(node_block.child_count().unwrap(), 0);
+        {
+            let child = node.create_child("child").unwrap();
+            let child_block = node.state.lock().heap.get_block(child.block_index).unwrap();
+            assert_eq!(child_block.block_type(), BlockType::NodeValue);
+            assert_eq!(child_block.child_count().unwrap(), 0);
+            assert_eq!(node_block.child_count().unwrap(), 1);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    #[test]
+    fn double_metric() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        {
+            let metric = node.create_double_metric("metric", 1.0).unwrap();
+            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
+            assert_eq!(metric_block.block_type(), BlockType::DoubleValue);
+            assert_eq!(metric_block.double_value().unwrap(), 1.0);
+            assert_eq!(node_block.child_count().unwrap(), 1);
+
+            assert!(metric.set(2.0).is_ok());
+            assert_eq!(metric_block.double_value().unwrap(), 2.0);
+
+            assert!(metric.subtract(5.5).is_ok());
+            assert_eq!(metric_block.double_value().unwrap(), -3.5);
+
+            assert!(metric.add(8.1).is_ok());
+            assert_eq!(metric_block.double_value().unwrap(), 4.6);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    #[test]
+    fn int_metric() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        {
+            let metric = node.create_int_metric("metric", 1).unwrap();
+            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
+            assert_eq!(metric_block.block_type(), BlockType::IntValue);
+            assert_eq!(metric_block.int_value().unwrap(), 1);
+            assert_eq!(node_block.child_count().unwrap(), 1);
+
+            assert!(metric.set(2).is_ok());
+            assert_eq!(metric_block.int_value().unwrap(), 2);
+
+            assert!(metric.subtract(5).is_ok());
+            assert_eq!(metric_block.int_value().unwrap(), -3);
+
+            assert!(metric.add(8).is_ok());
+            assert_eq!(metric_block.int_value().unwrap(), 5);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    #[test]
+    fn uint_metric() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        {
+            let metric = node.create_uint_metric("metric", 1).unwrap();
+            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
+            assert_eq!(metric_block.block_type(), BlockType::UintValue);
+            assert_eq!(metric_block.uint_value().unwrap(), 1);
+            assert_eq!(node_block.child_count().unwrap(), 1);
+
+            assert!(metric.set(5).is_ok());
+            assert_eq!(metric_block.uint_value().unwrap(), 5);
+
+            assert!(metric.subtract(3).is_ok());
+            assert_eq!(metric_block.uint_value().unwrap(), 2);
+
+            assert!(metric.add(8).is_ok());
+            assert_eq!(metric_block.uint_value().unwrap(), 10);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    #[test]
+    fn string_property() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        {
+            let property = node.create_property("property", "test").unwrap();
+            let property_block = node.state.lock().heap.get_block(property.block_index).unwrap();
+            assert_eq!(property_block.block_type(), BlockType::PropertyValue);
+            assert_eq!(property_block.property_total_length().unwrap(), 4);
+            assert_eq!(property_block.property_flags().unwrap(), constants::PROPERTY_FLAG_STRING);
+            assert_eq!(node_block.child_count().unwrap(), 1);
+
+            assert!(property.set("test-set").is_ok());
+            assert_eq!(property_block.property_total_length().unwrap(), 8);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    #[test]
+    fn bytevector_property() {
+        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
+        let state = get_state(mapping.clone());
+        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
+        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
+        {
+            let property = node.create_property("property", "test".as_bytes()).unwrap();
+            let property_block = node.state.lock().heap.get_block(property.block_index).unwrap();
+            assert_eq!(property_block.block_type(), BlockType::PropertyValue);
+            assert_eq!(property_block.property_total_length().unwrap(), 4);
+            assert_eq!(
+                property_block.property_flags().unwrap(),
+                constants::PROPERTY_FLAG_BYTE_VECTOR
+            );
+            assert_eq!(node_block.child_count().unwrap(), 1);
+
+            assert!(property.set("test-set".as_bytes()).is_ok());
+            assert_eq!(property_block.property_total_length().unwrap(), 8);
+        }
+        assert_eq!(node_block.child_count().unwrap(), 0);
+    }
+
+    fn get_state(mapping: Rc<Mapping>) -> Arc<Mutex<State>> {
+        let heap = Heap::new(mapping).unwrap();
+        Arc::new(Mutex::new(State::create(heap).unwrap()))
+    }
+}
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/reader.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/reader.rs
index efdebd89d6d5e79d6769037de3609a64402a4984..4c680e32e98804a091083faefc250d30bf2e0feb 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/reader.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/reader.rs
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#![cfg(test)]
+
 use crate::vmo::block::Block;
 use crate::vmo::utils;
 
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/state.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/state.rs
index 7b813aca85c1a4a8c4f623ce401a5fba16efd3d9..6aa1317110f8efa12cc118f797bf588c7d9826e2 100644
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/state.rs
+++ b/garnet/public/rust/fuchsia-inspect/src/vmo/state.rs
@@ -12,6 +12,7 @@ use crate::vmo::block_type::BlockType;
 use crate::vmo::constants;
 use crate::vmo::heap::Heap;
 use crate::vmo::utils;
+use crate::vmo::PropertyFormat;
 
 /// Wraps a heap and implements the Inspect VMO API on top of it at a low level.
 pub struct State {
@@ -19,58 +20,6 @@ pub struct State {
     header: Block<Rc<Mapping>>,
 }
 
-/// Provides functions required to implement formats for a property.
-pub trait PropertyFormat {
-    fn bytes(&self) -> &[u8];
-    fn flag(&self) -> u8;
-    fn length_in_bytes(&self) -> u32;
-}
-
-/// Implementation of property for a byte vector.
-impl PropertyFormat for &[u8] {
-    fn bytes(&self) -> &[u8] {
-        &self
-    }
-
-    fn flag(&self) -> u8 {
-        constants::PROPERTY_FLAG_BYTE_VECTOR
-    }
-
-    fn length_in_bytes(&self) -> u32 {
-        self.len().to_u32().unwrap()
-    }
-}
-
-/// Implementation of property for a string.
-impl PropertyFormat for &str {
-    fn bytes(&self) -> &[u8] {
-        self.as_bytes()
-    }
-
-    fn flag(&self) -> u8 {
-        constants::PROPERTY_FLAG_STRING
-    }
-
-    fn length_in_bytes(&self) -> u32 {
-        self.bytes().len().to_u32().unwrap()
-    }
-}
-
-/// Implementation of property for a string.
-impl PropertyFormat for String {
-    fn bytes(&self) -> &[u8] {
-        self.as_bytes()
-    }
-
-    fn flag(&self) -> u8 {
-        constants::PROPERTY_FLAG_STRING
-    }
-
-    fn length_in_bytes(&self) -> u32 {
-        self.bytes().len().to_u32().unwrap()
-    }
-}
-
 /// Locks the VMO Header blcok, executes the given codeblock and unblocks it.
 macro_rules! with_header_lock {
     ($self:ident, $code:block) => {{
diff --git a/garnet/public/rust/fuchsia-inspect/src/vmo/types.rs b/garnet/public/rust/fuchsia-inspect/src/vmo/types.rs
deleted file mode 100644
index 8e5cfcc40d2dfddcfc1771fad385f6c6088fdbd5..0000000000000000000000000000000000000000
--- a/garnet/public/rust/fuchsia-inspect/src/vmo/types.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use failure::Error;
-use parking_lot::Mutex;
-use paste;
-use std::marker::PhantomData;
-use std::sync::Arc;
-
-use crate::vmo::state::{PropertyFormat, State};
-
-/// Inspect API Node data type.
-pub struct Node {
-    /// Index of the block in the VMO.
-    block_index: u32,
-
-    /// Reference to the VMO heap.
-    state: Arc<Mutex<State>>,
-}
-
-/// Inspect API Metric data type.
-pub struct Metric<T: MetricFormat> {
-    /// Index of the block in the VMO.
-    block_index: u32,
-
-    /// Reference to the VMO heap.
-    state: Arc<Mutex<State>>,
-    phantom: PhantomData<T>,
-}
-
-/// Inspect API Property data type.
-pub struct Property<T: PropertyFormat> {
-    /// Index of the block in the VMO.
-    block_index: u32,
-
-    /// Reference to the VMO heap.
-    state: Arc<Mutex<State>>,
-    phantom: PhantomData<T>,
-}
-
-/// Allowed formats for a Metric data type (uint, int, double)
-pub trait MetricFormat {}
-impl MetricFormat for u64 {}
-impl MetricFormat for i64 {}
-impl MetricFormat for f64 {}
-
-/// Utility for generating functions to create a metric.
-///   `name`: identifier for the name (example: double)
-///   `type`: the type of the metric (example: f64)
-macro_rules! create_metric_fn {
-    ($name:ident, $type:ident) => {
-        paste::item! {
-            pub fn [<create_ $name _metric>](&self, name: &str, value: $type)
-                -> Result<Metric<$type>, Error> {
-                let block = self.state.lock().[<create_ $name _metric>](
-                    name, value, self.block_index)?;
-                Ok(Metric::<$type> {state: self.state.clone(), block_index: block.index(), phantom: PhantomData})
-            }
-        }
-    };
-}
-
-impl Node {
-    /// Allocate a new NODE object. Called through Inspector.
-    pub(in crate::vmo) fn allocate(
-        state: Arc<Mutex<State>>,
-        name: &str,
-        parent_index: u32,
-    ) -> Result<Self, Error> {
-        let block = state.lock().create_node(name, parent_index)?;
-        Ok(Node { state: state.clone(), block_index: block.index() })
-    }
-
-    /// Add a child to this node.
-    pub fn create_child(&self, name: &str) -> Result<Node, Error> {
-        let block = self.state.lock().create_node(name, self.block_index)?;
-        Ok(Node { state: self.state.clone(), block_index: block.index() })
-    }
-
-    /// Add a metric to this node: create_int_metric, create_double_metric,
-    /// create_uint_metric.
-    create_metric_fn!(int, i64);
-    create_metric_fn!(uint, u64);
-    create_metric_fn!(double, f64);
-
-    /// Add a property to this node.
-    pub fn create_property<T: PropertyFormat>(
-        &self,
-        name: &str,
-        value: T,
-    ) -> Result<Property<T>, Error> {
-        let block = self.state.lock().create_property(name, value, self.block_index)?;
-        Ok(Property::<T> {
-            state: self.state.clone(),
-            block_index: block.index(),
-            phantom: PhantomData,
-        })
-    }
-}
-
-impl Drop for Node {
-    fn drop(&mut self) {
-        self.state
-            .lock()
-            .free_value(self.block_index)
-            .expect(&format!("Failed to free node index={}", self.block_index));
-    }
-}
-
-/// Utility for generating metric functions (example: set, add, subtract)
-///   `fn_name`: the name of the function to generate (example: set)
-///   `type`: the type of the argument of the function to generate (example: f64)
-///   `name`: the readble name of the type of the function (example: double)
-macro_rules! metric_fn {
-    ($fn_name:ident, $type:ident, $name:ident) => {
-        paste::item! {
-            pub fn $fn_name(&self, value: $type) -> Result<(), Error> {
-                self.state.lock().[<$fn_name _ $name _metric>](self.block_index, value)
-            }
-        }
-    };
-}
-
-/// Utility for generating a metric datatype impl
-///   `name`: the readble name of the type of the function (example: double)
-///   `type`: the type of the argument of the function to generate (example: f64)
-macro_rules! metric_impl {
-    ($name:ident, $type:ident) => {
-        impl Metric<$type> {
-            metric_fn!(set, $type, $name);
-            metric_fn!(add, $type, $name);
-            metric_fn!(subtract, $type, $name);
-        }
-    };
-}
-
-metric_impl!(int, i64);
-metric_impl!(uint, u64);
-metric_impl!(double, f64);
-
-impl<T: MetricFormat> Drop for Metric<T> {
-    fn drop(&mut self) {
-        self.state
-            .lock()
-            .free_value(self.block_index)
-            .expect(&format!("Failed to free metric index={}", self.block_index));
-    }
-}
-
-impl<T: PropertyFormat> Property<T> {
-    /// Set a property value.
-    pub fn set(&self, value: T) -> Result<(), Error> {
-        self.state.lock().set_property(self.block_index, value)
-    }
-}
-
-impl<T: PropertyFormat> Drop for Property<T> {
-    fn drop(&mut self) {
-        self.state
-            .lock()
-            .free_property(self.block_index)
-            .expect(&format!("Failed to free property index={}", self.block_index));
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::vmo::block_type::BlockType;
-    use crate::vmo::constants;
-    use crate::vmo::heap::Heap;
-    use mapped_vmo::Mapping;
-    use std::rc::Rc;
-
-    #[test]
-    fn node() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        assert_eq!(node_block.block_type(), BlockType::NodeValue);
-        assert_eq!(node_block.child_count().unwrap(), 0);
-        {
-            let child = node.create_child("child").unwrap();
-            let child_block = node.state.lock().heap.get_block(child.block_index).unwrap();
-            assert_eq!(child_block.block_type(), BlockType::NodeValue);
-            assert_eq!(child_block.child_count().unwrap(), 0);
-            assert_eq!(node_block.child_count().unwrap(), 1);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    #[test]
-    fn double_metric() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        {
-            let metric = node.create_double_metric("metric", 1.0).unwrap();
-            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
-            assert_eq!(metric_block.block_type(), BlockType::DoubleValue);
-            assert_eq!(metric_block.double_value().unwrap(), 1.0);
-            assert_eq!(node_block.child_count().unwrap(), 1);
-
-            assert!(metric.set(2.0).is_ok());
-            assert_eq!(metric_block.double_value().unwrap(), 2.0);
-
-            assert!(metric.subtract(5.5).is_ok());
-            assert_eq!(metric_block.double_value().unwrap(), -3.5);
-
-            assert!(metric.add(8.1).is_ok());
-            assert_eq!(metric_block.double_value().unwrap(), 4.6);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    #[test]
-    fn int_metric() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        {
-            let metric = node.create_int_metric("metric", 1).unwrap();
-            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
-            assert_eq!(metric_block.block_type(), BlockType::IntValue);
-            assert_eq!(metric_block.int_value().unwrap(), 1);
-            assert_eq!(node_block.child_count().unwrap(), 1);
-
-            assert!(metric.set(2).is_ok());
-            assert_eq!(metric_block.int_value().unwrap(), 2);
-
-            assert!(metric.subtract(5).is_ok());
-            assert_eq!(metric_block.int_value().unwrap(), -3);
-
-            assert!(metric.add(8).is_ok());
-            assert_eq!(metric_block.int_value().unwrap(), 5);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    #[test]
-    fn uint_metric() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        {
-            let metric = node.create_uint_metric("metric", 1).unwrap();
-            let metric_block = node.state.lock().heap.get_block(metric.block_index).unwrap();
-            assert_eq!(metric_block.block_type(), BlockType::UintValue);
-            assert_eq!(metric_block.uint_value().unwrap(), 1);
-            assert_eq!(node_block.child_count().unwrap(), 1);
-
-            assert!(metric.set(5).is_ok());
-            assert_eq!(metric_block.uint_value().unwrap(), 5);
-
-            assert!(metric.subtract(3).is_ok());
-            assert_eq!(metric_block.uint_value().unwrap(), 2);
-
-            assert!(metric.add(8).is_ok());
-            assert_eq!(metric_block.uint_value().unwrap(), 10);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    #[test]
-    fn string_property() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        {
-            let property = node.create_property("property", "test").unwrap();
-            let property_block = node.state.lock().heap.get_block(property.block_index).unwrap();
-            assert_eq!(property_block.block_type(), BlockType::PropertyValue);
-            assert_eq!(property_block.property_total_length().unwrap(), 4);
-            assert_eq!(property_block.property_flags().unwrap(), constants::PROPERTY_FLAG_STRING);
-            assert_eq!(node_block.child_count().unwrap(), 1);
-
-            assert!(property.set("test-set").is_ok());
-            assert_eq!(property_block.property_total_length().unwrap(), 8);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    #[test]
-    fn bytevector_property() {
-        let mapping = Rc::new(Mapping::allocate(4096).unwrap().0);
-        let state = get_state(mapping.clone());
-        let node = Node::allocate(state, "root", constants::HEADER_INDEX).unwrap();
-        let node_block = node.state.lock().heap.get_block(node.block_index).unwrap();
-        {
-            let property = node.create_property("property", "test".as_bytes()).unwrap();
-            let property_block = node.state.lock().heap.get_block(property.block_index).unwrap();
-            assert_eq!(property_block.block_type(), BlockType::PropertyValue);
-            assert_eq!(property_block.property_total_length().unwrap(), 4);
-            assert_eq!(
-                property_block.property_flags().unwrap(),
-                constants::PROPERTY_FLAG_BYTE_VECTOR
-            );
-            assert_eq!(node_block.child_count().unwrap(), 1);
-
-            assert!(property.set("test-set".as_bytes()).is_ok());
-            assert_eq!(property_block.property_total_length().unwrap(), 8);
-        }
-        assert_eq!(node_block.child_count().unwrap(), 0);
-    }
-
-    fn get_state(mapping: Rc<Mapping>) -> Arc<Mutex<State>> {
-        let heap = Heap::new(mapping).unwrap();
-        Arc::new(Mutex::new(State::create(heap).unwrap()))
-    }
-}