weekend work
This commit is contained in:
+6
-1
@@ -6,8 +6,13 @@ autobenches = true
|
||||
|
||||
[dependencies]
|
||||
pretty_env_logger.workspace = true
|
||||
rand.workspace = true
|
||||
rand.workspace = true
|
||||
log.workspace = true
|
||||
# beep = "0.3.0"
|
||||
chrono.workspace = true
|
||||
dimensioned.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
flate2 = "1.0"
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
hex = "0.4.3"
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use flate2::{write::{GzEncoder, GzDecoder}, Compression};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about = "Compress or decompress a string", long_about = None)]
|
||||
struct Cli {
|
||||
/// Subcommand: either 'compress' or 'decompress'
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Compress the input string
|
||||
Compress {
|
||||
/// The string to compress
|
||||
input: String,
|
||||
},
|
||||
/// Decompress the input string (must be compressed format)
|
||||
Decompress {
|
||||
/// The compressed string to decompress, in hex format
|
||||
input: String,
|
||||
},
|
||||
}
|
||||
|
||||
fn compress_string(input: &str) -> Vec<u8> {
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||
encoder.write_all(input.as_bytes()).expect("Compression failed");
|
||||
encoder.finish().expect("Failed to finish compression")
|
||||
}
|
||||
|
||||
fn decompress_string(input: &[u8]) -> String {
|
||||
let mut decoder = GzDecoder::new(Vec::new());
|
||||
decoder.write_all(input).expect("Decompression failed");
|
||||
let decompressed_data = decoder.finish().expect("Failed to finish decompression");
|
||||
String::from_utf8(decompressed_data).expect("Invalid UTF-8")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
match cli.command {
|
||||
Commands::Compress { input } => {
|
||||
let compressed = compress_string(&input);
|
||||
// Convert to hex format for easier readability in the terminal
|
||||
println!("Compressed (hex): {:?} / from {}b to {}b", hex::encode(compressed.clone()), input.len(), compressed.len());
|
||||
}
|
||||
Commands::Decompress { input } => {
|
||||
// Decode hex string back to bytes
|
||||
let compressed_bytes = hex::decode(input).expect("Invalid hex input");
|
||||
let decompressed = decompress_string(&compressed_bytes);
|
||||
println!("Decompressed: {}", decompressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
use log::{debug};
|
||||
use crate::chip8::delay_timer::DelayTimer;
|
||||
use crate::chip8::keypad::Keypad;
|
||||
use crate::chip8::quirk_modes::QuirkMode;
|
||||
use crate::chip8::registers::Chip8Registers;
|
||||
use crate::chip8::sound_timer::SoundTimer;
|
||||
use crate::chip8::stack::Chip8Stack;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions,
|
||||
system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Chip8Computer {
|
||||
pub num_cycles: i32,
|
||||
pub memory: Chip8SystemMemory,
|
||||
@@ -21,7 +23,7 @@ pub struct Chip8Computer {
|
||||
pub state: Chip8CpuStates,
|
||||
pub keypad: Keypad,
|
||||
pub stack: Chip8Stack,
|
||||
pub quirk_mode: QuirkMode
|
||||
pub quirk_mode: QuirkMode,
|
||||
}
|
||||
impl Default for Chip8Computer {
|
||||
fn default() -> Self {
|
||||
@@ -35,7 +37,7 @@ impl Default for Chip8Computer {
|
||||
state: Chip8CpuStates::default(),
|
||||
keypad: Keypad::default(),
|
||||
stack: Chip8Stack::default(),
|
||||
quirk_mode: QuirkMode::default()
|
||||
quirk_mode: QuirkMode::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,13 +97,12 @@ impl Chip8Computer {
|
||||
// read the next instruction
|
||||
let local_memory = &self.memory;
|
||||
|
||||
// let mut working_instruction: u16 = 0b0000000000000000;
|
||||
// let mut working_instruction: u16 = 0b0000000000000000;
|
||||
let start_pc = self.registers.peek_pc();
|
||||
let high_byte = (local_memory.peek(start_pc) as u16).rotate_left(8);
|
||||
let low_byte = local_memory.peek(start_pc + 1) as u16;
|
||||
let result = high_byte | low_byte;
|
||||
let decoded_instruction =
|
||||
Chip8CpuInstructions::decode(result, &self.quirk_mode);
|
||||
let decoded_instruction = Chip8CpuInstructions::decode(result, &self.quirk_mode);
|
||||
// todo: THIS IS BAD AND IS A SIDE EFFECT
|
||||
decoded_instruction.execute(self);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#[derive(Clone, Copy, Default)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
|
||||
pub enum Chip8CpuStates {
|
||||
#[default]
|
||||
WaitingForInstruction,
|
||||
@@ -6,4 +8,3 @@ pub enum Chip8CpuStates {
|
||||
ExecutingInstruction,
|
||||
Error,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#[derive(Clone, Copy)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct DelayTimer {
|
||||
counter: u8
|
||||
counter: u8,
|
||||
}
|
||||
|
||||
impl Default for DelayTimer {
|
||||
@@ -15,9 +17,7 @@ impl DelayTimer {
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
DelayTimer {
|
||||
counter: 0xff
|
||||
}
|
||||
DelayTimer { counter: 0xff }
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::chip8::util::InstructionUtil;
|
||||
use crate::constants::*;
|
||||
use log::debug;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::ops::BitAnd;
|
||||
use std::time::Instant;
|
||||
@@ -18,7 +19,7 @@ y - A 4-bit value, the upper 4 bits of the low byte of the instruction
|
||||
kk or byte - An 8-bit value, the lowest 8 bits of the instruction
|
||||
*/
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Chip8CpuInstructions {
|
||||
/// 0nnn
|
||||
/// Exit to System Call at nnn
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::constants::CHIP8_KEYBOARD;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
|
||||
pub struct Keypad {
|
||||
keys: [bool; 0x10],
|
||||
}
|
||||
@@ -20,7 +21,6 @@ impl Keypad {
|
||||
|
||||
if index == 3 {
|
||||
return_value += format!("|{}|\n", is_lit).as_str();
|
||||
|
||||
} else {
|
||||
return_value += format!("|{}", is_lit).as_str();
|
||||
}
|
||||
@@ -31,7 +31,6 @@ impl Keypad {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Keypad {
|
||||
pub fn push_key(&mut self, key_index: u8) {
|
||||
self.keys[key_index as usize] = true;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#[derive(Default, Clone)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize)]
|
||||
pub enum QuirkMode {
|
||||
#[default]
|
||||
Chip8,
|
||||
XOChip,
|
||||
SChipModern
|
||||
SChipModern,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Registers. numbered 1-16 publicly.
|
||||
/// Privately using zero base array so -1 to shift from pub to priv.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Chip8Registers {
|
||||
pub registers: [u8; 16],
|
||||
pub i_register: u16,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use log::trace;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct SoundTimer {
|
||||
counter: i32
|
||||
counter: i32,
|
||||
}
|
||||
|
||||
impl Default for SoundTimer {
|
||||
@@ -16,9 +17,7 @@ impl SoundTimer {
|
||||
self.counter
|
||||
}
|
||||
pub fn new() -> Self {
|
||||
SoundTimer {
|
||||
counter: 0
|
||||
}
|
||||
SoundTimer { counter: 0 }
|
||||
}
|
||||
pub fn set_timer(&mut self, new_value: i32) {
|
||||
trace!("SETTING SOUND TIMER TO {new_value}");
|
||||
@@ -26,7 +25,11 @@ impl SoundTimer {
|
||||
}
|
||||
|
||||
pub fn tick(&mut self) {
|
||||
trace!("TICKING SOUND FROM {} to {}", self.counter, self.counter - 1);
|
||||
trace!(
|
||||
"TICKING SOUND FROM {} to {}",
|
||||
self.counter,
|
||||
self.counter - 1
|
||||
);
|
||||
if self.counter > 0 {
|
||||
self.counter -= 1;
|
||||
/*
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#[derive(Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct Chip8Stack {
|
||||
items: Vec<u16>
|
||||
}
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct Chip8Stack {
|
||||
items: Vec<u16>,
|
||||
}
|
||||
|
||||
impl Chip8Stack {
|
||||
pub fn push(&mut self, new_value: &u16) {
|
||||
if self.depth() == 16 {
|
||||
// println!("Deep deep stack?");
|
||||
panic!("Stack Overflow");
|
||||
// println!("Deep deep stack?");
|
||||
panic!("Stack Overflow");
|
||||
}
|
||||
self.items.push(*new_value );
|
||||
self.items.push(*new_value);
|
||||
}
|
||||
pub fn pop(&mut self) -> u16 {
|
||||
if self.items.is_empty() {
|
||||
@@ -24,9 +24,7 @@ impl Chip8Stack {
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Chip8Stack {
|
||||
items: vec![]
|
||||
}
|
||||
Chip8Stack { items: vec![] }
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
use log::{trace};
|
||||
use log::trace;
|
||||
|
||||
use crate::constants::*;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Chip8SystemMemory {
|
||||
memory: [u8; CHIP8_MEMORY_SIZE as usize],
|
||||
memory: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Default for Chip8SystemMemory {
|
||||
fn default() -> Self {
|
||||
|
||||
let mut x = Chip8SystemMemory {
|
||||
memory: [0x00; CHIP8_MEMORY_SIZE as usize],
|
||||
};
|
||||
let mut x = Chip8SystemMemory::new();
|
||||
|
||||
x.load_fonts_to_memory();
|
||||
x.load_schip_fonts_to_memory();
|
||||
@@ -20,27 +19,44 @@ impl Default for Chip8SystemMemory {
|
||||
}
|
||||
}
|
||||
impl Chip8SystemMemory {
|
||||
fn empty_memory() -> Vec<u8> {
|
||||
let mut working_memory = vec![];
|
||||
|
||||
pub fn reset(&mut self){
|
||||
self.memory = [0x00; CHIP8_MEMORY_SIZE as usize];
|
||||
for _ in 0..CHIP8_MEMORY_SIZE {
|
||||
working_memory.push(0x00);
|
||||
}
|
||||
working_memory
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.memory = Chip8SystemMemory::empty_memory();
|
||||
self.load_fonts_to_memory();
|
||||
self.load_schip_fonts_to_memory();
|
||||
}
|
||||
|
||||
|
||||
pub fn new() -> Self {
|
||||
Chip8SystemMemory {
|
||||
memory: [0x00; CHIP8_MEMORY_SIZE as usize],
|
||||
memory: Chip8SystemMemory::empty_memory(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&self, address: u16) -> u8 {
|
||||
trace!("PEEK: {} / {}", address, self.memory[address as usize].clone());
|
||||
trace!(
|
||||
"PEEK: {} / {}",
|
||||
address,
|
||||
self.memory[address as usize].clone()
|
||||
);
|
||||
let effective = address as i32 % CHIP8_MEMORY_SIZE;
|
||||
self.memory[effective as usize]
|
||||
}
|
||||
|
||||
pub fn poke(&mut self, address: u16, value: u8) {
|
||||
trace!("POKE: {} / {} to {}", address, self.memory[address as usize], value);
|
||||
pub fn poke(&mut self, address: u16, value: u8) {
|
||||
trace!(
|
||||
"POKE: {} / {} to {}",
|
||||
address,
|
||||
self.memory[address as usize],
|
||||
value
|
||||
);
|
||||
self.memory[address as usize] = value;
|
||||
}
|
||||
|
||||
@@ -80,10 +96,22 @@ impl Chip8SystemMemory {
|
||||
|
||||
pub fn load_schip_fonts_to_memory(&mut self) {
|
||||
let all_font_characters = [
|
||||
SCHIPFONT_0, SCHIPFONT_1, SCHIPFONT_2, SCHIPFONT_3,
|
||||
SCHIPFONT_4, SCHIPFONT_5, SCHIPFONT_6, SCHIPFONT_7,
|
||||
SCHIPFONT_8, SCHIPFONT_9, SCHIPFONT_A, SCHIPFONT_B,
|
||||
SCHIPFONT_C, SCHIPFONT_D, SCHIPFONT_E, SCHIPFONT_F
|
||||
SCHIPFONT_0,
|
||||
SCHIPFONT_1,
|
||||
SCHIPFONT_2,
|
||||
SCHIPFONT_3,
|
||||
SCHIPFONT_4,
|
||||
SCHIPFONT_5,
|
||||
SCHIPFONT_6,
|
||||
SCHIPFONT_7,
|
||||
SCHIPFONT_8,
|
||||
SCHIPFONT_9,
|
||||
SCHIPFONT_A,
|
||||
SCHIPFONT_B,
|
||||
SCHIPFONT_C,
|
||||
SCHIPFONT_D,
|
||||
SCHIPFONT_E,
|
||||
SCHIPFONT_F,
|
||||
];
|
||||
for (font_index, current_font) in all_font_characters.iter().enumerate() {
|
||||
let base_offset = 0x100;
|
||||
@@ -93,4 +121,4 @@ impl Chip8SystemMemory {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+32
-19
@@ -1,14 +1,18 @@
|
||||
use log::{debug};
|
||||
use crate::chip8::video::Chip8VideoModes::{HighRes, LowRes};
|
||||
use crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH};
|
||||
use crate::constants::{
|
||||
CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT,
|
||||
SCHIP_VIDEO_WIDTH, SCHIP_VIDE_MEMORY,
|
||||
};
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum Chip8VideoModes {
|
||||
LowRes,
|
||||
HighRes,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Chip8Video {
|
||||
memory: Vec<bool>,
|
||||
pub has_frame_changed: bool,
|
||||
@@ -42,12 +46,8 @@ impl Chip8Video {
|
||||
pub fn cls(&mut self) {
|
||||
self.memory.clear();
|
||||
let num_loops = match self.current_res {
|
||||
LowRes => {
|
||||
CHIP8_VIDEO_MEMORY
|
||||
}
|
||||
HighRes => {
|
||||
SCHIP_VIDE_MEMORY
|
||||
}
|
||||
LowRes => CHIP8_VIDEO_MEMORY,
|
||||
HighRes => SCHIP_VIDE_MEMORY,
|
||||
};
|
||||
for i in 0..num_loops {
|
||||
self.memory.push(false);
|
||||
@@ -74,7 +74,9 @@ impl Chip8Video {
|
||||
};
|
||||
let effective_address = if address >= loop_value {
|
||||
address % loop_value
|
||||
} else { address };
|
||||
} else {
|
||||
address
|
||||
};
|
||||
self.memory[effective_address as usize]
|
||||
}
|
||||
|
||||
@@ -84,8 +86,8 @@ impl Chip8Video {
|
||||
let effective_address = address % loop_value;
|
||||
|
||||
let old_value = self.memory[effective_address as usize];
|
||||
let xored_value = new_value ^ old_value; // XOR of the video
|
||||
// if the frame has already changed we dont care if it changed again.
|
||||
let xored_value = new_value ^ old_value; // XOR of the video
|
||||
// if the frame has already changed we dont care if it changed again.
|
||||
if !self.has_frame_changed && old_value != xored_value {
|
||||
self.has_frame_changed = true
|
||||
}
|
||||
@@ -103,7 +105,10 @@ impl Chip8Video {
|
||||
pub fn poke_2byte(&mut self, first_address: u16, to_write: [u8; 2]) {
|
||||
for (idx, _) in to_write.iter().enumerate() {
|
||||
for i in (0..8).rev() {
|
||||
self.poke(first_address + (idx * 8) as u16 + (7 - i), (to_write[idx] & (1 << i)) != 0);
|
||||
self.poke(
|
||||
first_address + (idx * 8) as u16 + (7 - i),
|
||||
(to_write[idx] & (1 << i)) != 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +120,10 @@ impl Chip8Video {
|
||||
for row in 0..height {
|
||||
for column in 0..width {
|
||||
let data_offset = row * width + column;
|
||||
debug!("Rendering {data_offset} with value {}", self.memory[data_offset as usize]);
|
||||
debug!(
|
||||
"Rendering {data_offset} with value {}",
|
||||
self.memory[data_offset as usize]
|
||||
);
|
||||
if self.memory[data_offset as usize] {
|
||||
output += "*"
|
||||
} else {
|
||||
@@ -200,7 +208,6 @@ impl Chip8Video {
|
||||
self.memory[clear_start..].fill(false);
|
||||
}
|
||||
|
||||
|
||||
pub fn scroll_down(&mut self, how_far: i32) {
|
||||
let (width, height) = self.get_resolution();
|
||||
let row_shift = how_far * width;
|
||||
@@ -212,7 +219,7 @@ impl Chip8Video {
|
||||
let base_offset: usize = (current_source_offset + current_source_column) as usize;
|
||||
let extended_offset: usize = base_offset + row_shift as usize;
|
||||
self.memory[extended_offset] = self.memory[base_offset];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the new top rows after shifting
|
||||
@@ -224,7 +231,13 @@ impl Chip8Video {
|
||||
impl Default for Chip8Video {
|
||||
fn default() -> Self {
|
||||
let mut mem = vec![];
|
||||
for _ in 0..CHIP8_VIDEO_MEMORY { mem.push(false); }
|
||||
Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes }
|
||||
for _ in 0..CHIP8_VIDEO_MEMORY {
|
||||
mem.push(false);
|
||||
}
|
||||
Chip8Video {
|
||||
memory: mem,
|
||||
has_frame_changed: false,
|
||||
current_res: Chip8VideoModes::LowRes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
use flate2::write::{GzEncoder, GzDecoder};
|
||||
use flate2::Compression;
|
||||
use std::io::prelude::*;
|
||||
use gemma::chip8::computer::Chip8Computer;
|
||||
|
||||
fn load_result(to_load: &str) -> String {
|
||||
std::fs::read_to_string(format!("resources/test/state/{}", to_load)).unwrap()
|
||||
}
|
||||
|
||||
fn load_compressed_result(to_load: &str) -> String {
|
||||
// load the file...
|
||||
// ...then uncompress the string.
|
||||
let mut decoder = GzDecoder::new(Vec::new());
|
||||
decoder.write_all(load_result(to_load).as_ref()).expect("Decompression failed");
|
||||
let decompressed_data = decoder.finish().expect("Failed to finish decompression");
|
||||
String::from_utf8(decompressed_data).expect("Invalid UTF-8")
|
||||
}
|
||||
|
||||
fn load_rom(to_load: &str) -> Vec<u8> {
|
||||
std::fs::read(format!("resources/roms/{}", to_load)).unwrap()
|
||||
}
|
||||
#[test]
|
||||
fn smoke_round_trip_serialize_deserialize() {
|
||||
let x = Chip8Computer::new();
|
||||
let expected_string = load_result("smoke_001_round_trip_serialize_deserialize.json");
|
||||
let serialized = serde_json::to_string(&x).unwrap();
|
||||
let deserialized: Chip8Computer = serde_json::from_str(&expected_string).unwrap();
|
||||
println!("SERIALIZED [{}]", serialized);
|
||||
// TODO: using trim here is a hack to handle editors adding a newline at the end of a file...even a 1 line file
|
||||
assert_eq!(serialized.trim(), expected_string.trim());
|
||||
assert_eq!(deserialized, x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn computer_001_system_zero_state() {
|
||||
let x = Chip8Computer::new();
|
||||
let expected_string = load_compressed_result("smoke_002_round_trip_serialize_deserialize.tflt");
|
||||
let serialized = serde_json::to_string(&x).unwrap();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user