parent
1579b5d82c
commit
84c3197fac
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "logicworld-subassembly"]
|
||||||
|
path = logicworld-subassembly
|
||||||
|
url = git@gitea.d4vid.xyz:D4VID/logicworld-subassembly.git
|
@ -1,47 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 4
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "binary_serialize_derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.101"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.40"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.106"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
|
@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "binary_serialize_derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc-macro2 = "1.0.101"
|
|
||||||
quote = "1.0.40"
|
|
||||||
syn = { version = "2.0.106", features = ["full"] }
|
|
@ -1,36 +0,0 @@
|
|||||||
extern crate proc_macro;
|
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use quote::quote;
|
|
||||||
use syn::{parse_macro_input, DeriveInput};
|
|
||||||
|
|
||||||
#[proc_macro_derive(BinarySerializable)]
|
|
||||||
pub fn derive_binary_serializable(input: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
|
||||||
|
|
||||||
let name = input.ident;
|
|
||||||
|
|
||||||
let fields = match input.data {
|
|
||||||
syn::Data::Struct(s) => s.fields,
|
|
||||||
_ => panic!("#[derive(BinarySerializable)] only works on structs"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let field_writes = fields.iter().map(|f| {
|
|
||||||
let ident = f.ident.as_ref().unwrap();
|
|
||||||
quote! {
|
|
||||||
BinarySerializable::write_to(&self.#ident, writer)?;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let expanded = quote! {
|
|
||||||
impl BinarySerializable for #name {
|
|
||||||
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
|
||||||
#(#field_writes)*
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(expanded)
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 3ff75d8d16e7e676160da21889cce2992ee912b3
|
@ -1,149 +0,0 @@
|
|||||||
use std::io::{self, Write};
|
|
||||||
|
|
||||||
use binary_serialize_derive::BinarySerializable;
|
|
||||||
use quaternion::Quaternion;
|
|
||||||
use vecmath::Vector3;
|
|
||||||
|
|
||||||
pub trait BinarySerializable {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum PegType {
|
|
||||||
Input = 1,
|
|
||||||
Output = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type int = i32;
|
|
||||||
pub type float = f32;
|
|
||||||
pub type ComponentAddress = u32;
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct Version {
|
|
||||||
pub major: int,
|
|
||||||
pub minor: int,
|
|
||||||
pub build: int,
|
|
||||||
pub revision: int,
|
|
||||||
}
|
|
||||||
impl Version {
|
|
||||||
pub fn new(major: int, minor: int, build: int, revision: int) -> Self {
|
|
||||||
Self {
|
|
||||||
major,
|
|
||||||
minor,
|
|
||||||
build,
|
|
||||||
revision,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct ModVersion {
|
|
||||||
pub id: String,
|
|
||||||
pub version: Version,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct Input {
|
|
||||||
circuit_state_id: int,
|
|
||||||
}
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct Output {
|
|
||||||
circuit_state_id: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct ComponentIdMap {
|
|
||||||
pub numeric_id: i16,
|
|
||||||
pub text_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct PegAddress {
|
|
||||||
peg_type: PegType,
|
|
||||||
component_address: ComponentAddress,
|
|
||||||
index: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct Component {
|
|
||||||
pub address: ComponentAddress,
|
|
||||||
pub parent: ComponentAddress,
|
|
||||||
pub numeric_id: u16,
|
|
||||||
pub position: Vector3<int>,
|
|
||||||
pub rotation: Quaternion<float>,
|
|
||||||
pub inputs: Vec<Input>,
|
|
||||||
pub outputs: Vec<Output>,
|
|
||||||
pub custom_data: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BinarySerializable)]
|
|
||||||
pub struct Wire {
|
|
||||||
first_point: PegAddress,
|
|
||||||
second_point: PegAddress,
|
|
||||||
circuit_state_id: int,
|
|
||||||
wire_rotation: float,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: BinarySerializable> BinarySerializable for Vec<T> {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&(self.len() as int).to_le_bytes())?;
|
|
||||||
for value in self {
|
|
||||||
value.write_to(writer)?;
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinarySerializable for Vec<u8> {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&(self.len() as int).to_le_bytes())?;
|
|
||||||
writer.write_all(&self)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinarySerializable for PegType {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&[*self as u8])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinarySerializable for String {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&(self.len() as int).to_le_bytes())?;
|
|
||||||
writer.write_all(self.as_bytes())?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinarySerializable for Vector3<int> {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&self[0].to_le_bytes())?; // x
|
|
||||||
writer.write_all(&self[1].to_le_bytes())?; // y
|
|
||||||
writer.write_all(&self[2].to_le_bytes())?; // z
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinarySerializable for Quaternion<float> {
|
|
||||||
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&self.1[0].to_le_bytes())?; // x
|
|
||||||
writer.write_all(&self.1[1].to_le_bytes())?; // y
|
|
||||||
writer.write_all(&self.1[2].to_le_bytes())?; // z
|
|
||||||
writer.write_all(&self.0.to_le_bytes())?; // w
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_binary_num {
|
|
||||||
($($t:ty),*) => {
|
|
||||||
$(impl BinarySerializable for $t {
|
|
||||||
fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
|
||||||
writer.write_all(&self.to_le_bytes())
|
|
||||||
}
|
|
||||||
})*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_binary_num!(i16, u16, i32, u32, f32);
|
|
@ -1,102 +0,0 @@
|
|||||||
use std::{
|
|
||||||
i32,
|
|
||||||
io::{self, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::lw::{self, BinarySerializable, ComponentIdMap, ModVersion, Version};
|
|
||||||
|
|
||||||
enum SaveType {
|
|
||||||
World = 1,
|
|
||||||
Subassembly = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_subassembly_file(
|
|
||||||
file: &mut impl Write,
|
|
||||||
components: &[lw::Component],
|
|
||||||
wires: &[lw::Wire],
|
|
||||||
) -> io::Result<()> {
|
|
||||||
// Header:
|
|
||||||
file.write_all(b"Logic World save")?; // Magic bytes
|
|
||||||
file.write_all(&[7 as u8])?; // Version 7
|
|
||||||
Version::new(0, 92, 0, 455).write_to(file)?; // Game Version
|
|
||||||
file.write_all(&[SaveType::Subassembly as u8])?;
|
|
||||||
|
|
||||||
(components.len() as i32).write_to(file)?;
|
|
||||||
(wires.len() as i32).write_to(file)?;
|
|
||||||
|
|
||||||
// Body:
|
|
||||||
let mods = vec![ModVersion {
|
|
||||||
id: "MHG".to_owned(),
|
|
||||||
version: Version::new(0, 91, 4, -1),
|
|
||||||
}];
|
|
||||||
mods.write_to(file)?;
|
|
||||||
|
|
||||||
let component_id_map = vec![ComponentIdMap {
|
|
||||||
numeric_id: 15,
|
|
||||||
text_id: "MHG.CircuitBoard".to_owned(),
|
|
||||||
}];
|
|
||||||
component_id_map.write_to(file)?;
|
|
||||||
|
|
||||||
for component in components {
|
|
||||||
component.write_to(file)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for wire in wires {
|
|
||||||
wire.write_to(file)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
0i32.write_to(file)?; // We don't have any turned on nets
|
|
||||||
|
|
||||||
file.write_all(b"redstone sux lol")?; // Footer
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_placing_info_file(file: &mut impl Write) -> io::Result<()> {
|
|
||||||
file.write_all(
|
|
||||||
b"PlacingInfo:
|
|
||||||
RaiseOnChangedEvents: true
|
|
||||||
Flipped: false
|
|
||||||
RotationAboutUpVector: 180
|
|
||||||
Offset:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
BoardIsFlat: true
|
|
||||||
BoardRotationState: 0
|
|
||||||
",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub fn write_placements_file(file: &mut impl Write) -> io::Result<()> {
|
|
||||||
file.write_all(
|
|
||||||
b"Placements:
|
|
||||||
-
|
|
||||||
CornerMidpointPositionBeforeFlipping:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
z: 0
|
|
||||||
RotationBeforeFlipping:
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
z: 0
|
|
||||||
w: 1
|
|
||||||
PlacementType: OnTerrain
|
|
||||||
Flipped: false
|
|
||||||
BoardRotationState: 0
|
|
||||||
Type: Standard
|
|
||||||
data_format_version: 1
|
|
||||||
",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_meta_file(file: &mut impl Write, title: &str) -> io::Result<()> {
|
|
||||||
file.write_all(
|
|
||||||
format!(
|
|
||||||
"Title: {}
|
|
||||||
Column: null
|
|
||||||
Category: null
|
|
||||||
",
|
|
||||||
title
|
|
||||||
)
|
|
||||||
.as_bytes(),
|
|
||||||
)
|
|
||||||
}
|
|
@ -0,0 +1,60 @@
|
|||||||
|
use std::{
|
||||||
|
fs::File, io::{self, Read}, process::{Command, Stdio}
|
||||||
|
};
|
||||||
|
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
ExitCode(i32),
|
||||||
|
Terminated,
|
||||||
|
TempDir,
|
||||||
|
NoOutput,
|
||||||
|
Execute,
|
||||||
|
IO(io::Error),
|
||||||
|
InvalidJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(value: io::Error) -> Self {
|
||||||
|
Self::IO(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> Result<(), Error> {
|
||||||
|
let tmp = tempdir().map_err(|_| Error::TempDir)?;
|
||||||
|
let tmp_file_path = tmp.path().join("modules.json");
|
||||||
|
|
||||||
|
let mut command = Command::new("yosys");
|
||||||
|
command.args(["-o", tmp_file_path.to_str().unwrap(), "-p", yosys_command]);
|
||||||
|
command.args(files);
|
||||||
|
|
||||||
|
if let Some(module) = module {
|
||||||
|
command.args(["-r", module]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = command
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.status()
|
||||||
|
.map_err(|_| Error::Execute)?;
|
||||||
|
|
||||||
|
if let Some(code) = result.code() {
|
||||||
|
if code != 0 {
|
||||||
|
return Err(Error::ExitCode(code));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::Terminated);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file = File::open(tmp_file_path).map_err(|_| Error::NoOutput)?;
|
||||||
|
let mut file_contents = String::new();
|
||||||
|
file.read_to_string(&mut file_contents)?;
|
||||||
|
|
||||||
|
println!("{}", file_contents);
|
||||||
|
|
||||||
|
let object = json::parse(&file_contents).map_err(|_| Error::InvalidJson)?;
|
||||||
|
|
||||||
|
println!("{:?}", object["modules"]);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
Loading…
Reference in new issue