Skip to content

WIP serde #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ log = "0.3"
arrayvec = "0.4"
rustc-serialize = "0.3"
lazy_static = { version = "0.2", optional = true }
serde = "1.0"
serde_derive = "1.0"

[lib]
name = "rustation"
Expand Down
2 changes: 1 addition & 1 deletion cdimage
2 changes: 1 addition & 1 deletion src/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ impl Assembler {
.cop_r(cop_r))
}

/// Alignment padding
// Alignment padding
Align(o) =>
for _ in 0..pad_to_order(self.location(), o) {
self.emit_byte(0);
Expand Down
136 changes: 136 additions & 0 deletions src/bigarray.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//! Workaround for big arrays (len > 32), see https://github.com/serde-rs/serde/issues/631

use std::fmt;
use std::marker::PhantomData;
use serde::ser::{Serialize, Serializer, SerializeTuple};
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};

pub trait BigArray<'de>: Sized {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer;
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>;
}

macro_rules! big_array {
($($len:expr,)+) => {
$(
impl<'de, T> BigArray<'de> for [T; $len]
where T: Default + Copy + Serialize + Deserialize<'de>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut seq = serializer.serialize_tuple(self.len())?;
for elem in &self[..] {
seq.serialize_element(elem)?;
}
seq.end()
}

fn deserialize<D>(deserializer: D) -> Result<[T; $len], D::Error>
where D: Deserializer<'de>
{
struct ArrayVisitor<T> {
element: PhantomData<T>,
}

impl<'de, T> Visitor<'de> for ArrayVisitor<T>
where T: Default + Copy + Deserialize<'de>
{
type Value = [T; $len];

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("an array of length ", $len))
}

fn visit_seq<A>(self, mut seq: A) -> Result<[T; $len], A::Error>
where A: SeqAccess<'de>
{
let mut arr = [T::default(); $len];
for i in 0..$len {
arr[i] = seq.next_element()?
.ok_or_else(|| Error::invalid_length(i, &self))?;
}
Ok(arr)
}
}

let visitor = ArrayVisitor { element: PhantomData };
deserializer.deserialize_tuple($len, visitor)
}
}
)+
}
}

big_array! {
1024,
2097152,
}



pub trait BigArrayBox<'de>: Sized {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer;
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>;
}

macro_rules! big_array_box {
($($len:expr,)+) => {
$(
impl<'de, T> BigArrayBox<'de> for Box<[T; $len]>
where T: Default + Copy + Serialize + Deserialize<'de>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut seq = serializer.serialize_tuple(self.len())?;
for elem in &self[..] {
seq.serialize_element(elem)?;
}
seq.end()
}

fn deserialize<D>(deserializer: D) -> Result<Box<[T; $len]>, D::Error>
where D: Deserializer<'de>
{
struct ArrayVisitor<T> {
element: PhantomData<T>,
}

impl<'de, T> Visitor<'de> for ArrayVisitor<T>
where T: Default + Copy + Deserialize<'de>
{
type Value = Box<[T; $len]>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("an array of length ", $len))
}

fn visit_seq<A>(self, mut seq: A) -> Result<Box<[T; $len]>, A::Error>
where A: SeqAccess<'de>
{
let mut arr = Box::new([T::default(); $len]);
for i in 0..$len {
arr[i] = seq.next_element()?
.ok_or_else(|| Error::invalid_length(i, &self))?;
}
Ok(arr)
}
}

let visitor = ArrayVisitor { element: PhantomData };
deserializer.deserialize_tuple($len, visitor)
}
}
)+
}
}

big_array_box! {
2097152, // RAM_SIZE
524288, // VRAM_SIZE_PIXELS
}
79 changes: 47 additions & 32 deletions src/bios/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use rustc_serialize::{Decodable, Encodable, Decoder, Encoder};
use std::fmt;

use serde::ser::{Serializer, Serialize, SerializeSeq};
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};

use memory::Addressable;
use cdrom::disc::Region;
Expand Down Expand Up @@ -110,43 +113,55 @@ impl Bios {
}
}

impl Encodable for Bios {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
// We don't store the full BIOS image in the savestate, mainly
// because I want to be able to share and distribute
// savestates without having to worry about legal
// implications. Let's just serialize the checksum to make
// sure we use the correct BIOS when loading the savestate.

let sha256 = &self.metadata.sha256;
impl Serialize for Bios {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let sha256 = &self.metadata.sha256;

s.emit_seq(sha256.len(), |s| {
for (i, b) in sha256.iter().enumerate() {
try!(s.emit_seq_elt(i, |s| b.encode(s)));
let mut seq = serializer.serialize_seq(Some(sha256.len()))?;
for e in sha256 {
seq.serialize_element(e)?;
}
Ok(())
})
}
seq.end()
}
}

impl Decodable for Bios {
fn decode<D: Decoder>(d: &mut D) -> Result<Bios, D::Error> {
d.read_seq(|d, len| {
let mut sha256 = [0; 32];

if len != sha256.len() {
return Err(d.error("wrong BIOM checksum length"));
impl<'de> Deserialize<'de> for Bios {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
struct Sha256Visitor;

impl<'de> Visitor<'de> for Sha256Visitor
{
type Value = [u8; 32];

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an array of length 32")
}

fn visit_seq<A>(self, mut seq: A) -> Result<[u8; 32], A::Error>
where
A: SeqAccess<'de>,
{
let mut arr = [0u8; 32];
for i in 0..32 {
arr[i] = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
}
Ok(arr)
}
}

for (i, b) in sha256.iter_mut().enumerate() {
*b = try!(d.read_seq_elt(i, |d| Decodable::decode(d)))
}
let sha256: [u8; 32] = deserializer.deserialize_seq(Sha256Visitor)?;

let meta =
match db::lookup_sha256(&sha256) {
Some(m) => m,
None => return Err(d.error("unknown BIOS checksum")),
};
// try to lookup the sha256
let meta = db::lookup_sha256(&sha256)
.ok_or_else(|| Error::custom("unknown BIOS checksum"))?;

// Create an "empty" BIOS instance, only referencing the
// metadata. It's up to the caller to fill the blanks.
Expand All @@ -155,10 +170,10 @@ impl Decodable for Bios {
bios.metadata = meta;

Ok(bios)
})
}
}
}


/// Dummy metadata used as a placeholder for dummy BIOS instances
static DUMMY_METADATA: Metadata =
Metadata {
Expand Down
33 changes: 10 additions & 23 deletions src/cdrom/disc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@ use cdimage::msf::Msf;
use cdimage::bcd::Bcd;
use cdimage::sector::Sector;

use rustc_serialize::{Decodable, Encodable, Decoder, Encoder};

use super::iso9660;

/// PlayStation disc.
///
/// XXX: add support for CD-DA? Not really useful but shouldn't
/// be very hard either. We need to support audio tracks anyway...
#[derive(Serialize, Deserialize)]
pub struct Disc {
/// Image file
#[serde(skip)]
#[serde(default = "default_image")]
image: Box<Image>,
/// Disc serial number
serial: SerialNumber,
}


pub fn default_image() -> Box<Image> {
Box::new(MissingImage)
}

impl Disc {
/// Reify a disc using `image` as a backend.
pub fn new(mut image: Box<Image>) -> Result<Disc, String> {
Expand Down Expand Up @@ -58,25 +64,6 @@ impl Disc {
}
}

impl Encodable for Disc {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
// Only encode the serial number
self.serial.encode(s)
}
}

impl Decodable for Disc {
fn decode<D: Decoder>(d: &mut D) -> Result<Disc, D::Error> {
let serial = try!(SerialNumber::decode(d));

// Placeholder disc image
Ok(Disc {
image: Box::new(MissingImage),
serial: serial,
})
}
}

/// Dummy Image implemementation used when deserializing a Disc. Since
/// we don't want to store the entire disc in the image it will be
/// missing after a load, it's up to the frontend to make sure to
Expand All @@ -98,7 +85,7 @@ impl Image for MissingImage {
}

/// Disc region
#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcDecodable, RustcEncodable)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Region {
/// Japan (NTSC): SCEI
Japan,
Expand All @@ -109,7 +96,7 @@ pub enum Region {
}

/// Disc serial number
#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SerialNumber([u8; 10]);

impl SerialNumber {
Expand Down
Loading