为固定大小的向量周围的包装器实现Decodable

时间:2014-08-17 10:09:24

标签: serialization rust

背景:序列化包没有文档,导出Decodable不起作用。我还查看了其他类型的现有实现,并发现难以遵循的代码。

解码过程如何工作,以及如何为此结构实现Decodable?

pub struct Grid<A> {
    data: [[A,..GRIDW],..GRIDH]
}

#[deriving(Decodable)]不起作用的原因是[A,..GRIDW]没有实现Decodable,并且当在这个crate之外定义两者时,不可能为类型实现特征,这是这里的情况。因此,我能看到的唯一解决方案是手动实现Decodable for Grid。

就我而言,这是

impl <A: Decodable<D, E>, D: Decoder<E>, E> Decodable<D, E> for Grid<A> {
    fn decode(decoder: &mut D) -> Result<Grid<A>, E> {
        decoder.read_struct("Grid", 1u, ref |d| Ok(Grid {
            data: match d.read_struct_field("data", 0u, ref |d| Decodable::decode(d)) {
                Ok(e) => e,
                Err(e) => return Err(e)
            },
        }))
    }
}

这会在Decodable::decode(d)

时出错
  

错误:未能找到特征的实现   serialize :: serialize :: [[A,.. 20],.. 20]

的可解码

1 个答案:

答案 0 :(得分:2)

由于各种原因,目前不太可能做得很好:

  • 在固定长度数组(基本问题)
  • 的长度上,我们不能通用
  • 当前的特质一致性限制意味着我们无法使用trait MyDecodable<D, E> { ... }(一个用于impl MyDecodable<D, E> for [A, .. GRIDW])和一揽子实施GRIDH来编写自定义impl<A: Decodable<D, E>> MyDecodable<D, E> for A。这迫使基于特质的解决方案使用中间类型,这使得编译器的类型推断相当不愉快,AFAICT无法满足。
  • 我们没有关联类型(又名&#34;输出类型&#34;),我认为这样可以让类型推断略显合理。

因此,目前,我们已经手动实施了。 :(

extern crate serialize;

use std::default::Default;
use serialize::{Decoder, Decodable};

static GRIDW: uint = 10;
static GRIDH: uint = 5;


fn decode_grid<E, D: Decoder<E>,
               A: Copy + Default + Decodable<D, E>>(d: &mut D) 
        -> Result<Grid<A>, E> {
    // mirror the Vec implementation: try to read a sequence
    d.read_seq(|d, len| {
        // check it's the required length
        if len != GRIDH {
            return Err(
                d.error(format!("expecting length {} but found {}", 
                                GRIDH, len).as_slice()));
        }
        // create the array with empty values ...
        let mut array: [[A, .. GRIDW], .. GRIDH] 
            = [[Default::default(), .. GRIDW], .. GRIDH];

        // ... and fill it in progressively ...
        for (i, outer) in array.mut_iter().enumerate() {
            // ... by reading each outer element ... 
            try!(d.read_seq_elt(i, |d| {
                //  ... as a sequence ...
                d.read_seq(|d, len| {
                    // ... of the right length,
                    if len != GRIDW { return Err(d.error("...")) }

                    // and then read each element of that sequence as the
                    // elements of the grid.
                    for (j, inner) in outer.mut_iter().enumerate() {
                        *inner = try!(d.read_seq_elt(j, Decodable::decode));
                    }
                    Ok(())
                })
            }));
        }

        // all done successfully!
        Ok(Grid { data: array })
    })
}


pub struct Grid<A> {
    data: [[A,..GRIDW],..GRIDH]
}

impl<E, D: Decoder<E>, A: Copy + Default + Decodable<D, E>> 
    Decodable<D, E> for Grid<A> {
    fn decode(d: &mut D) -> Result<Grid<A>, E> {
        d.read_struct("Grid", 1, |d| {
            d.read_struct_field("data", 0, decode_grid)
        })
    }
}

fn main() {}

playpen

也可以写一个更多&#34;泛型&#34; [T, .. n]解码器使用macros来实例化每个版本,特别控制如何处理递归解码以允许处理嵌套的固定长度数组(根据Grid的要求);这需要更少的代码(特别是有更多的层,或各种不同的长度),但宏解决方案:

  • 可能更难理解,
  • 我给的那个可能效率较低(为每个固定长度数组创建一个新的array变量,包括新的Default s,而上面的非宏解决方案只使用一个array,因此只对网格中的每个元素调用一次Default::default。有可能扩展到一组类似的递归循环,但我不确定。