Repository: bluss/rust-ndarray
Pull request #212 (2016-08-12 12:42:34)

Use serde 0.8
Builds upon #115 


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 1592bb9f..c2d25b96 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "ndarray"
-version = "0.6.1"
+version = "0.6.0"
 authors = ["bluss"]
 license = "MIT/Apache-2.0"
 
@@ -39,15 +39,23 @@ optional = true
 blas-sys = { version = "0.6.3", optional = true, default-features = false }
 matrixmultiply = { version = "0.1.8" }
 
+[dependencies.serde]
+version = "0.8"
+optional = true
+
+[dev-dependencies.serde_json]
+version = "0.8"
+
+
 [features]
 blas = ["blas-sys"]
 
 # These features are used for testing
 blas-openblas-sys = ["blas"]
-test = ["blas-openblas-sys", "rustc-serialize"]
+test = ["blas-openblas-sys", "rustc-serialize", "serde"]
 
 # This feature is used for docs
-docs = ["rustc-serialize"]
+docs = ["rustc-serialize", "serde"]
 
 [profile.release]
 [profile.bench]
diff --git a/README.rst b/README.rst
index ac6e47b6..128c491e 100644
--- a/README.rst
+++ b/README.rst
@@ -72,7 +72,12 @@ your `Cargo.toml`.
 - ``rustc-serialize``
 
   - Optional, compatible with Rust stable
-  - Enables serialization support
+  - Enables serialization support for rustc-serialize 0.3
+
+- ``serde``
+
+  - Optional, compatible with Rust stable
+  - Enables serialization support for serde 0.8
 
 - ``blas``
 
@@ -83,17 +88,11 @@ your `Cargo.toml`.
 How to use with cargo::
 
     [dependencies]
-    ndarray = "0.6"
+    ndarray = "0.5"
 
 Recent Changes (ndarray)
 ------------------------
 
-- 0.6.1
-
-  - Add ``unsafe`` array view constructors ``ArrayView::from_shape_ptr``
-    for read-only and read-write array views. These make it easier to
-    create views from raw pointers.
-
 - 0.6.0
 
   - Rename ``OwnedArray`` to ``Array``. The old name is deprecated.
diff --git a/build.rs b/build.rs
index 3a84d91e..385a423f 100644
--- a/build.rs
+++ b/build.rs
@@ -4,7 +4,6 @@
 ///
 
 fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
     if cfg!(feature = "blas-openblas-sys") {
         println!("cargo:rustc-link-lib={}=openblas", "dylib");
     }
diff --git a/src/arraydeserialize.rs b/src/arraydeserialize.rs
new file mode 100644
index 00000000..97633d15
--- /dev/null
+++ b/src/arraydeserialize.rs
@@ -0,0 +1,122 @@
+// Copyright 2014-2016 bluss and ndarray developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+use serde::{self, Deserialize};
+
+use std::marker::PhantomData;
+
+use imp_prelude::*;
+
+use super::arraytraits::ARRAY_FORMAT_VERSION;
+
+struct ArrayVisitor<S, Di> {
+    _marker_a: PhantomData<S>,
+    _marker_b: PhantomData<Di>,
+}
+
+enum ArrayField {
+    Version,
+    Dim,
+    Data,
+}
+
+impl<S, Di> ArrayVisitor<S, Di> {
+    pub fn new() -> Self {
+        ArrayVisitor { _marker_a: PhantomData, _marker_b: PhantomData, }
+    }
+}
+
+/// **Requires crate feature `"serde"`**
+impl<A, Di, S> Deserialize for ArrayBase<S, Di>
+    where A: Deserialize,
+          Di: Deserialize + Dimension,
+          S: DataOwned<Elem = A>
+{
+    fn deserialize<D>(deserializer: &mut D) -> Result<ArrayBase<S, Di>, D::Error>
+        where D: serde::de::Deserializer
+    {
+        static FIELDS: &'static [&'static str] = &["v", "dim", "data"];
+
+        deserializer.deserialize_struct("Array", FIELDS, ArrayVisitor::new())
+    }
+}
+
+impl serde::de::Deserialize for ArrayField {
+    fn deserialize<D>(deserializer: &mut D) -> Result<ArrayField, D::Error>
+        where D: serde::de::Deserializer
+    {
+        struct ArrayFieldVisitor;
+
+        impl serde::de::Visitor for ArrayFieldVisitor {
+            type Value = ArrayField;
+
+            fn visit_str<E>(&mut self, value: &str) -> Result<ArrayField, E>
+                where E: serde::de::Error
+            {
+                match value {
+                    "v" => Ok(ArrayField::Version),
+                    "data" => Ok(ArrayField::Data),
+                    "dim" => Ok(ArrayField::Dim),
+                    _ => Err(serde::de::Error::custom("expected v, data, or dim")),
+                }
+            }
+        }
+
+        deserializer.deserialize(ArrayFieldVisitor)
+    }
+}
+
+impl<A, Di, S> serde::de::Visitor for ArrayVisitor<S,Di>
+    where A: Deserialize,
+          Di: Deserialize + Dimension,
+          S: DataOwned<Elem = A>
+{
+    type Value = ArrayBase<S, Di>;
+
+    fn visit_map<V>(&mut self, mut visitor: V) -> Result<ArrayBase<S, Di>, V::Error>
+        where V: serde::de::MapVisitor,
+    {
+        let mut v: Option<u8> = None;
+        let mut data: Option<Vec<A>> = None;
+        let mut dim: Option<Di> = None;
+
+        loop {
+            match try!(visitor.visit_key()) {
+                Some(ArrayField::Version) => { v = Some(try!(visitor.visit_value())); },
+                Some(ArrayField::Data) => { data = Some(try!(visitor.visit_value())); },
+                Some(ArrayField::Dim) => { dim = Some(try!(visitor.visit_value())); },
+                None => { break; },
+            }
+        }
+
+        let v = match v {
+            Some(v) => v,
+            None => try!(visitor.missing_field("v")),
+        };
+
+        if v != ARRAY_FORMAT_VERSION {
+            try!(Err(serde::de::Error::custom(format!("unknown array version: {}", v))));
+        }
+
+        let data = match data {
+            Some(data) => data,
+            None => try!(visitor.missing_field("data")),
+        };
+
+        let dim = match dim {
+            Some(dim) => dim,
+            None => try!(visitor.missing_field("dim")),
+        };
+
+        if let Ok(array) = ArrayBase::from_shape_vec(dim, data) {
+            try!(visitor.end());
+            Ok(array)
+        } else {
+            Err(serde::de::Error::custom("data and dimension must match in size"))
+        }
+    }
+}
diff --git a/src/arrayserialize.rs b/src/arrayserialize.rs
index d4723a13..8341aee2 100644
--- a/src/arrayserialize.rs
+++ b/src/arrayserialize.rs
@@ -5,63 +5,46 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-use serde::ser::impls::SeqIteratorVisitor;
-use serde::{self, Serialize, Deserialize};
+use serde::{self, Serialize};
 
-use super::{
-    Array,
-    Dimension,
-    Ix,
-    Elements,
-};
+use imp_prelude::*;
 
-struct AVisitor<'a, A: 'a, D: 'a> {
-    arr: &'a RcArray<A, D>,
-    state: u32,
-}
+use super::arraytraits::ARRAY_FORMAT_VERSION;
+use super::Elements;
 
-impl<A: Serialize, D: Serialize> Serialize for RcArray<A, D>
-    where D: Dimension
-{
-    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
-        where S: serde::Serializer
-    {
-        serializer.visit_named_map("Array",
-                                   AVisitor {
-                                       arr: self,
-                                       state: 0,
-                                   })
-    }
-}
+/// **Requires crate feature `"serde"`**
+impl<A, D, S> Serialize for ArrayBase<S, D>
+    where A: Serialize,
+          D: Dimension + Serialize,
+          S: Data<Elem = A>
 
-impl<'a, A: Serialize, D: Serialize> Serialize for Elements<'a, A, D>
-    where D: Dimension
 {
-    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
-        where S: serde::Serializer
+    fn serialize<Se>(&self, serializer: &mut Se) -> Result<(), Se::Error>
+        where Se: serde::Serializer
     {
-        serializer.visit_seq(SeqIteratorVisitor::new(self.clone(), None))
+        let mut struct_state = try!(serializer.serialize_struct("Array", 3));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "v", ARRAY_FORMAT_VERSION));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "dim", self.dim()));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "data", Sequence(self.iter())));
+        serializer.serialize_struct_end(struct_state)
     }
 }
 
-impl<'a, A, D> serde::ser::MapVisitor for AVisitor<'a, A, D>
+// private iterator wrapper
+struct Sequence<'a, A: 'a, D>(Elements<'a, A, D>);
+
+impl<'a, A, D> Serialize for Sequence<'a, A, D>
     where A: Serialize,
-          D: Serialize + Dimension
+          D: Dimension + Serialize
 {
-    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
+    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
         where S: serde::Serializer
     {
-        match self.state {
-            0 => {
-                self.state += 1;
-                Ok(Some(try!(serializer.visit_map_elt("shape", self.arr.dim()))))
-            }
-            1 => {
-                self.state += 1;
-                Ok(Some(try!(serializer.visit_map_elt("data", self.arr.iter()))))
-            }
-            _ => Ok(None),
+        let iter = &self.0;
+        let mut seq_state = try!(serializer.serialize_seq(Some(iter.len())));
+        for elt in iter.clone() {
+            try!(serializer.serialize_seq_elt(&mut seq_state, elt));
         }
-
+        serializer.serialize_seq_end(seq_state)
     }
 }
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index b357765c..64bbf9e5 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -208,10 +208,9 @@ unsafe impl<S, D> Send for ArrayBase<S, D>
     where S: Send + Data, D: Send
 { }
 
-
-#[cfg(feature = "rustc-serialize")]
+#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
 // Use version number so we can add a packed format later.
-static ARRAY_FORMAT_VERSION: u8 = 1u8;
+pub const ARRAY_FORMAT_VERSION: u8 = 1u8;
 
 /// **Requires crate feature `"rustc-serialize"`**
 #[cfg(feature = "rustc-serialize")]
@@ -256,6 +255,7 @@ impl<A, S, D> Decodable for ArrayBase<S, D>
             let dim: D = try!(d.read_struct_field("dim", 1, |d| {
                 Decodable::decode(d)
             }));
+
             let elements = try!(
                 d.read_struct_field("data", 2, |d| {
                     d.read_seq(|d, len| {
diff --git a/src/impl_2d.rs b/src/impl_2d.rs
index 6413d776..dc1792e5 100644
--- a/src/impl_2d.rs
+++ b/src/impl_2d.rs
@@ -31,7 +31,7 @@ impl<A, S> ArrayBase<S, (Ix, Ix)>
     }
 
     /// Return the number of rows (length of `Axis(0)`) in the two-dimensional array.
-    pub fn rows(&self) -> usize {
+    pub fn rows(&self) -> Ix {
         self.shape().axis(Axis(0))
     }
 
@@ -53,7 +53,7 @@ impl<A, S> ArrayBase<S, (Ix, Ix)>
     }
 
     /// Return the number of columns (length of `Axis(1)`) in the two-dimensional array.
-    pub fn cols(&self) -> usize {
+    pub fn cols(&self) -> Ix {
         self.shape().axis(Axis(1))
     }
 }
diff --git a/src/impl_views.rs b/src/impl_views.rs
index f8d6bc65..5b6e4dd3 100644
--- a/src/impl_views.rs
+++ b/src/impl_views.rs
@@ -59,20 +59,6 @@ impl<'a, A, D> ArrayBase<ViewRepr<&'a A>, D>
         })
     }
 
-    /// Create an `ArrayView<A, D>` from shape information and a
-    /// raw pointer to the elements.
-    ///
-    /// Unsafe because caller is responsible for ensuring that the pointer is
-    /// valid, not mutably aliased and coherent with the dimension and stride information.
-    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
-        where Sh: Into<StrideShape<D>>
-    {
-        let shape = shape.into();
-        let dim = shape.dim;
-        let strides = shape.strides;
-        ArrayView::new_(ptr, dim, strides)
-    }
-
     /// Split the array along `axis` and return one view strictly before the
     /// split and one view after the split.
     ///
@@ -162,20 +148,6 @@ impl<'a, A, D> ArrayBase<ViewRepr<&'a mut A>, D>
         })
     }
 
-    /// Create an `ArrayViewMut<A, D>` from shape information and a
-    /// raw pointer to the elements.
-    ///
-    /// Unsafe because caller is responsible for ensuring that the pointer is
-    /// valid, not aliased and coherent with the dimension and stride information.
-    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
-        where Sh: Into<StrideShape<D>>
-    {
-        let shape = shape.into();
-        let dim = shape.dim;
-        let strides = shape.strides;
-        ArrayViewMut::new_(ptr, dim, strides)
-    }
-
     /// Split the array along `axis` and return one mutable view strictly
     /// before the split and one mutable view after the split.
     ///
diff --git a/src/lib.rs b/src/lib.rs
index 7a9a4d0e..262e8ed6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,7 +57,10 @@
 //!
 //! - `rustc-serialize`
 //!   - Optional, compatible with Rust stable
-//!   - Enables serialization support
+//!   - Enables serialization support for rustc-serialize 0.3
+//! - `serde`
+//!   - Optional, compatible with Rust stable
+//!   - Enables serialization support for serde 0.8
 //! - `blas`
 //!   - Optional and experimental, compatible with Rust stable
 //!   - Enable transparent BLAS support for matrix multiplication. Pluggable
@@ -114,6 +117,8 @@ pub use shape_builder::{ ShapeBuilder };
 mod arraytraits;
 #[cfg(feature = "serde")]
 mod arrayserialize;
+#[cfg(feature = "serde")]
+mod arraydeserialize;
 mod arrayformat;
 mod data_traits;
 


Test patch:
diff --git a/tests/array.rs b/tests/array.rs
index fa496953..1aeeede8 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -1036,17 +1036,3 @@ fn test_shape() {
     assert_eq!(b.strides(), &[1, 1, 2]);
     assert_eq!(c.strides(), &[1, 3, 1]);
 }
-
-#[test]
-fn test_view_from_shape_ptr() {
-    let data = [0, 1, 2, 3, 4, 5];
-    let view = unsafe { ArrayView::from_shape_ptr((2, 3), data.as_ptr()) };
-    assert_eq!(view, aview2(&[[0, 1, 2], [3, 4, 5]]));
-
-    let mut data = data;
-    let mut view = unsafe { ArrayViewMut::from_shape_ptr((2, 3), data.as_mut_ptr()) };
-    view[[1, 2]] = 6;
-    assert_eq!(view, aview2(&[[0, 1, 2], [3, 4, 6]]));
-    view[[0, 1]] = 0;
-    assert_eq!(view, aview2(&[[0, 0, 2], [3, 4, 6]]));
-}
diff --git a/tests/serialize.rs b/tests/serialize.rs
index 1a7f5261..0b515365 100644
--- a/tests/serialize.rs
+++ b/tests/serialize.rs
@@ -6,45 +6,14 @@ extern crate ndarray;
 #[cfg(feature = "serde")]
 extern crate serde;
 
+#[cfg(feature = "serde")]
+extern crate serde_json;
+
 #[cfg(feature = "rustc-serialize")]
 use serialize::json;
 
 use ndarray::{arr0, arr1, arr2, RcArray, Ix, S, Si};
 
-#[cfg(feature = "serde")]
-#[test]
-fn test_serde()
-{
-    let mut out = std::io::stdout();
-    {
-        let a = arr0::<f32>(2.72);
-        println!("{:?}", a);
-        let v = serde::json::to_value(&a);
-        serde::json::to_writer(&mut out, &a);
-        /*
-        let serial = serde::json::encode(&a).unwrap();
-        println!("Encode {:?} => {:?}", a, serial);
-        */
-        //let res = json::decode::<RcArray<f32, _>>(&serial);
-        //println!("{:?}", res);
-        //assert_eq!(a, res.unwrap());
-    }
-
-    {
-        let a = arr2(&[[2.7, 1., 2.],
-                       [ 1., 0., 1.]]);
-        println!("{:?}", a);
-        serde::json::to_writer(&mut out, &a);
-        /*
-        let serial = serde::json::encode(&a).unwrap();
-        println!("{:?}", serial);
-        let res = json::decode::<RcArray<f32, _>>(&serial);
-        println!("{:?}", res);
-        assert_eq!(a, res.unwrap());
-        */
-    }
-}
-
 #[cfg(feature = "rustc-serialize")]
 #[test]
 fn serial_many_dim()
@@ -60,9 +29,8 @@ fn serial_many_dim()
 
     {
         let a = arr1::<f32>(&[2.72, 1., 2.]);
-        println!("{:?}", a);
         let serial = json::encode(&a).unwrap();
-        println!("{:?}", serial);
+        println!("Encode {:?} => {:?}", a, serial);
         let res = json::decode::<RcArray<f32, _>>(&serial);
         println!("{:?}", res);
         assert_eq!(a, res.unwrap());
@@ -70,9 +38,8 @@ fn serial_many_dim()
 
     {
         let a = arr2(&[[3., 1., 2.2], [3.1, 4., 7.]]);
-        println!("{:?}", a);
         let serial = json::encode(&a).unwrap();
-        println!("{:?}", serial);
+        println!("Encode {:?} => {:?}", a, serial);
         let res = json::decode::<RcArray<f32, _>>(&serial);
         println!("{:?}", res);
         assert_eq!(a, res.unwrap());
@@ -86,9 +53,8 @@ fn serial_many_dim()
         // Test a sliced array.
         let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
         a.islice(&[Si(0, None, -1), S, S, Si(0, Some(2), 1)]);
-        println!("{:?}", a);
         let serial = json::encode(&a).unwrap();
-        println!("{:?}", serial);
+        println!("Encode {:?} => {:?}", a, serial);
         let res = json::decode::<RcArray<f32, _>>(&serial);
         println!("{:?}", res);
         assert_eq!(a, res.unwrap());
@@ -111,3 +77,66 @@ fn serial_wrong_count()
     println!("{:?}", arr);
     assert!(arr.is_err());
 }
+
+#[cfg(feature = "serde")]
+#[test]
+fn serial_many_dim_serde()
+{
+    {
+        let a = arr0::<f32>(2.72);
+        let serial = serde_json::to_string(&a).unwrap();
+        println!("Serde encode {:?} => {:?}", a, serial);
+        let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
+        println!("{:?}", res);
+        assert_eq!(a, res.unwrap());
+    }
+
+    {
+        let a = arr1::<f32>(&[2.72, 1., 2.]);
+        let serial = serde_json::to_string(&a).unwrap();
+        println!("Serde encode {:?} => {:?}", a, serial);
+        let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
+        println!("{:?}", res);
+        assert_eq!(a, res.unwrap());
+    }
+
+    {
+        let a = arr2(&[[3., 1., 2.2], [3.1, 4., 7.]]);
+        let serial = serde_json::to_string(&a).unwrap();
+        println!("Serde encode {:?} => {:?}", a, serial);
+        let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
+        println!("{:?}", res);
+        assert_eq!(a, res.unwrap());
+        let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##;
+        let b = serde_json::from_str::<RcArray<f32, (Ix, Ix)>>(text);
+        assert_eq!(a, b.unwrap());
+    }
+
+    {
+        // Test a sliced array.
+        let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
+        a.islice(&[Si(0, None, -1), S, S, Si(0, Some(2), 1)]);
+        let serial = serde_json::to_string(&a).unwrap();
+        println!("Encode {:?} => {:?}", a, serial);
+        let res = serde_json::from_str::<RcArray<f32, _>>(&serial);
+        println!("{:?}", res);
+        assert_eq!(a, res.unwrap());
+    }
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn serial_wrong_count_serde()
+{
+    // one element too few
+    let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4]}"##;
+    let arr = serde_json::from_str::<RcArray<f32, (Ix, Ix)>>(text);
+    println!("{:?}", arr);
+    assert!(arr.is_err());
+
+    // future version
+    let text = r##"{"v":200,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##;
+    let arr = serde_json::from_str::<RcArray<f32, (Ix, Ix)>>(text);
+    println!("{:?}", arr);
+    assert!(arr.is_err());
+}