use preserves::{de, value::{self, Reader, IOBinarySource, BinarySource}};
use serde::{Serialize, Deserialize};
use std::fs::File;
use std::io;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Fruit {
    Apple(Colour),
    Pear(Variety),
    Banana(Weight, Colour, u8),

    // Peach,

    #[serde(other)]
    Unknown,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename = "kilograms")]
struct Weight(f32);

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Colour {
    name: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Variety {
    Conference,
    Bosc,
    European,
    Anjou,
}

fn try_file(kind: &str, path: &str) -> io::Result<()> {
    let fruits_value = IOBinarySource::new(&mut File::open(path)?).packed_iovalues().demand_next(true)?;
    println!("{:#?}", fruits_value);

    let fruits1: Vec<Fruit> = value::de::from_value(&fruits_value)?;
    println!("(via generic decoding) {}: {:?}", kind, fruits1);

    let fruits2: Vec<Fruit> = de::from_read(&mut File::open(path)?)?;
    println!("(direct from binary)   {}: {:?}\n", kind, fruits2);

    assert_eq!(fruits1, fruits2);
    Ok(())
}

fn main() -> io::Result<()> {
    try_file("KNOWN", "examples/known-data.bin")?;
    try_file("UNKNOWN", "examples/unknown-data.bin")?;
    Ok(())
}
