Remove serde (#23)
This commit is contained in:
25
.github/workflows/rust.yml
vendored
25
.github/workflows/rust.yml
vendored
@@ -193,6 +193,31 @@ jobs:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
round_trip:
|
||||||
|
{
|
||||||
|
"name": "Round-trip generator and consumer",
|
||||||
|
"runs-on": "ubuntu-latest",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"uses": "actions/checkout@v3",
|
||||||
|
"name": "Checkout"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Install Nix",
|
||||||
|
"uses": "cachix/install-nix-action@v17",
|
||||||
|
"with": { "extra-nix-config": "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Run generator",
|
||||||
|
"run": "nix develop . --command cargo run --release --bin generator --package generator -- 12345 100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Run consumer",
|
||||||
|
"run": "nix develop . --command cargo run --release --bin haversine-app --package haversine-app -- data_100_flex.json data_100_haveranswer.f64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
all-required-checks-complete:
|
all-required-checks-complete:
|
||||||
{
|
{
|
||||||
"needs":
|
"needs":
|
||||||
|
49
Cargo.lock
generated
49
Cargo.lock
generated
@@ -189,9 +189,8 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"clap",
|
"clap",
|
||||||
"haversine",
|
"haversine",
|
||||||
|
"json",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -208,9 +207,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "haversine"
|
name = "haversine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "haversine-app"
|
name = "haversine-app"
|
||||||
@@ -258,12 +254,6 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "json"
|
name = "json"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -376,43 +366,6 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.163"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.163"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.96"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sim-wrapper"
|
name = "sim-wrapper"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@@ -10,6 +10,5 @@ edition = "2021"
|
|||||||
clap = { version = "4.3.1", features = [ "derive" ] }
|
clap = { version = "4.3.1", features = [ "derive" ] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
haversine = { path = "../haversine" }
|
haversine = { path = "../haversine" }
|
||||||
serde_json = "1.0.96"
|
json = { path = "../json" }
|
||||||
serde = "1.0.163"
|
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use clap::{builder::PossibleValue, Parser, ValueEnum};
|
use clap::{builder::PossibleValue, Parser, ValueEnum};
|
||||||
use haversine::haversine::{CoordinatePair, HaversineData};
|
use haversine::haversine::{CoordinatePair, HaversineData};
|
||||||
use haversine::{distance, earth};
|
use haversine::{distance, earth};
|
||||||
|
use json::json_object::JsonValue;
|
||||||
use rand::distributions::Distribution;
|
use rand::distributions::Distribution;
|
||||||
use rand::rngs::StdRng;
|
use rand::rngs::StdRng;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
@@ -63,10 +64,41 @@ fn write_json(data: &HaversineData, json_filename: &str) {
|
|||||||
let output_file = File::create(json_filename).unwrap();
|
let output_file = File::create(json_filename).unwrap();
|
||||||
let mut writer = BufWriter::new(output_file);
|
let mut writer = BufWriter::new(output_file);
|
||||||
|
|
||||||
serde_json::to_writer(&mut writer, &data).unwrap();
|
writer.write_all(r#"{"pairs":["#.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut is_first = true;
|
||||||
|
for point in data.pairs.iter() {
|
||||||
|
if !is_first {
|
||||||
|
writer.write_all(&[b',']).unwrap();
|
||||||
|
}
|
||||||
|
writer.write_all(&[b'{']).unwrap();
|
||||||
|
writer
|
||||||
|
.write_all(
|
||||||
|
format!(
|
||||||
|
r#""x0":{:.17},"y0":{:.17},"x1":{:.17},"y1":{:.17}"#,
|
||||||
|
point.x0, point.y0, point.x1, point.y1
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writer.write_all(&[b'}']).unwrap();
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write_all("]}".as_bytes()).unwrap();
|
||||||
writer.flush().unwrap();
|
writer.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Our JSON parser is incapable of round-tripping floats, for precision reasons.
|
||||||
|
// To work around this, we'll just compute using the serialised versions.
|
||||||
|
fn round_trip_float(f: f64) -> f64 {
|
||||||
|
let written = format!("{:.17}", f);
|
||||||
|
JsonValue::parse(&mut written.chars())
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.as_number()
|
||||||
|
}
|
||||||
|
|
||||||
fn write_answer(data: &HaversineData, binary_filename: &str) {
|
fn write_answer(data: &HaversineData, binary_filename: &str) {
|
||||||
let output_file = File::create(binary_filename).unwrap();
|
let output_file = File::create(binary_filename).unwrap();
|
||||||
let mut writer = BufWriter::new(output_file);
|
let mut writer = BufWriter::new(output_file);
|
||||||
@@ -75,8 +107,15 @@ fn write_answer(data: &HaversineData, binary_filename: &str) {
|
|||||||
|
|
||||||
let mut buf = [0u8; 8];
|
let mut buf = [0u8; 8];
|
||||||
for (count, point) in data.pairs.iter().enumerate() {
|
for (count, point) in data.pairs.iter().enumerate() {
|
||||||
let distance = distance::naive(point, earth::RADIUS);
|
let point = CoordinatePair {
|
||||||
LittleEndian::write_f64(&mut buf, distance);
|
x0: round_trip_float(point.x0),
|
||||||
|
y0: round_trip_float(point.y0),
|
||||||
|
x1: round_trip_float(point.x1),
|
||||||
|
y1: round_trip_float(point.y1),
|
||||||
|
};
|
||||||
|
|
||||||
|
let distance = distance::naive(&point, earth::RADIUS);
|
||||||
|
BigEndian::write_f64(&mut buf, distance);
|
||||||
|
|
||||||
let written = writer.write(&buf).unwrap();
|
let written = writer.write(&buf).unwrap();
|
||||||
if written < buf.len() {
|
if written < buf.len() {
|
||||||
@@ -90,7 +129,7 @@ fn write_answer(data: &HaversineData, binary_filename: &str) {
|
|||||||
// sic!
|
// sic!
|
||||||
println!("Expected sum: {}", expected_average);
|
println!("Expected sum: {}", expected_average);
|
||||||
|
|
||||||
LittleEndian::write_f64(&mut buf, expected_average);
|
BigEndian::write_f64(&mut buf, expected_average);
|
||||||
let written = writer.write(&buf).unwrap();
|
let written = writer.write(&buf).unwrap();
|
||||||
if written < buf.len() {
|
if written < buf.len() {
|
||||||
panic!("Failed to write everything")
|
panic!("Failed to write everything")
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
use byteorder::{ByteOrder, LittleEndian};
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use haversine::haversine::CoordinatePair;
|
use haversine::haversine::CoordinatePair;
|
||||||
use haversine::{distance, earth};
|
use haversine::{distance, earth};
|
||||||
use json::json_object::JsonValue;
|
use json::json_object::JsonValue;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
|
use std::process::ExitCode;
|
||||||
use utf8_read::Reader;
|
use utf8_read::Reader;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -41,7 +41,7 @@ fn read_answer(binary_filename: &str) -> (Vec<f64>, f64) {
|
|||||||
bytes_read += new_bytes;
|
bytes_read += new_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.push(LittleEndian::read_f64(&buf));
|
data.push(f64::from_be_bytes(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes_read = file.read(&mut buf).unwrap();
|
let bytes_read = file.read(&mut buf).unwrap();
|
||||||
@@ -49,7 +49,7 @@ fn read_answer(binary_filename: &str) -> (Vec<f64>, f64) {
|
|||||||
panic!("Not enough bytes read")
|
panic!("Not enough bytes read")
|
||||||
}
|
}
|
||||||
|
|
||||||
(data, LittleEndian::read_f64(&buf))
|
(data, f64::from_be_bytes(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_json(json_filename: &str) -> Vec<CoordinatePair> {
|
fn read_json(json_filename: &str) -> Vec<CoordinatePair> {
|
||||||
@@ -77,23 +77,35 @@ fn read_json(json_filename: &str) -> Vec<CoordinatePair> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn haversine_sum(v: &[CoordinatePair]) -> f64 {
|
fn haversine_sum(v: &[CoordinatePair], reference: &[f64]) -> f64 {
|
||||||
let mut answer = 0.0_f64;
|
let mut answer = 0.0_f64;
|
||||||
for pair in v {
|
for (count, pair) in v.iter().enumerate() {
|
||||||
answer += distance::naive(pair, earth::RADIUS);
|
let computed = distance::naive(pair, earth::RADIUS);
|
||||||
|
if computed != reference[count] {
|
||||||
|
println!("Different! At index {}, received pair: {:?}, computed distance {computed}, expected {}", count, pair, reference[count])
|
||||||
|
}
|
||||||
|
answer =
|
||||||
|
((1.0 - (1.0 / (count as f64 + 1.0))) * answer) + (computed / (count as f64 + 1.0));
|
||||||
}
|
}
|
||||||
answer / (v.len() as f64)
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), ExitCode> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let input = read_json(&args.input_json);
|
let input = read_json(&args.input_json);
|
||||||
let (_expected_values, expected_sum) = read_answer(&args.expected);
|
let (expected_values, expected_sum) = read_answer(&args.expected);
|
||||||
let actual_sum = haversine_sum(&input);
|
let actual_sum = haversine_sum(&input, &expected_values);
|
||||||
println!("Pair count: {}", input.len());
|
println!("Pair count: {}", input.len());
|
||||||
println!("Haversine sum: {}", actual_sum);
|
println!("Haversine sum: {}", actual_sum);
|
||||||
|
|
||||||
println!("Validation:");
|
println!("Validation:");
|
||||||
println!("Reference sum: {}", expected_sum);
|
println!("Reference sum: {}", expected_sum);
|
||||||
println!("Difference: {}", f64::abs(expected_sum - actual_sum));
|
let difference = f64::abs(expected_sum - actual_sum);
|
||||||
|
println!("Difference: {}", difference);
|
||||||
|
|
||||||
|
if difference != 0.0 {
|
||||||
|
return Err(ExitCode::FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@@ -8,4 +8,3 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.163", features = [ "derive" ] }
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
use serde::Serialize;
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
pub struct CoordinatePair {
|
pub struct CoordinatePair {
|
||||||
pub x0: f64,
|
pub x0: f64,
|
||||||
pub y0: f64,
|
pub y0: f64,
|
||||||
@@ -8,7 +7,22 @@ pub struct CoordinatePair {
|
|||||||
pub y1: f64,
|
pub y1: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
impl Debug for CoordinatePair {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"x0: {} ({:?}), y0: {} ({:?}), x1: {} ({:?}), y1: {} ({:?})",
|
||||||
|
self.x0,
|
||||||
|
self.x0.to_be_bytes(),
|
||||||
|
self.y0,
|
||||||
|
self.y0.to_be_bytes(),
|
||||||
|
self.x1,
|
||||||
|
self.x1.to_be_bytes(),
|
||||||
|
self.y1,
|
||||||
|
self.y1.to_be_bytes()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct HaversineData {
|
pub struct HaversineData {
|
||||||
pub pairs: Vec<CoordinatePair>,
|
pub pairs: Vec<CoordinatePair>,
|
||||||
}
|
}
|
||||||
|
@@ -132,8 +132,8 @@ where
|
|||||||
{
|
{
|
||||||
let mut current = current;
|
let mut current = current;
|
||||||
let mut negative = 1.0;
|
let mut negative = 1.0;
|
||||||
let mut integer_part = 0f64;
|
let mut result = 0f64;
|
||||||
let mut fractional_part = 0f64;
|
let mut fraction = 0f64;
|
||||||
|
|
||||||
if current == '-' {
|
if current == '-' {
|
||||||
negative = -1.0;
|
negative = -1.0;
|
||||||
@@ -149,14 +149,14 @@ where
|
|||||||
None => return Ok((negative * 0.0, None)),
|
None => return Ok((negative * 0.0, None)),
|
||||||
}
|
}
|
||||||
} else if ('1'..='9').contains(¤t) {
|
} else if ('1'..='9').contains(¤t) {
|
||||||
integer_part = (current as u8 - b'0') as f64;
|
result = (current as u8 - b'0') as f64;
|
||||||
loop {
|
loop {
|
||||||
current = match iter.next() {
|
current = match iter.next() {
|
||||||
None => return Ok((negative * integer_part, None)),
|
None => return Ok((negative * result, None)),
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
if current.is_ascii_digit() {
|
if current.is_ascii_digit() {
|
||||||
integer_part = integer_part * 10.0 + ((current as u8 - b'0') as f64)
|
result = result * 10.0 + ((current as u8 - b'0') as f64)
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -170,11 +170,11 @@ where
|
|||||||
let mut multiplier = 0.1;
|
let mut multiplier = 0.1;
|
||||||
loop {
|
loop {
|
||||||
current = match iter.next() {
|
current = match iter.next() {
|
||||||
None => return Ok((negative * (integer_part + fractional_part), None)),
|
None => return Ok((negative * (result + fraction), None)),
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
if current.is_ascii_digit() {
|
if current.is_ascii_digit() {
|
||||||
fractional_part += multiplier * ((current as u8 - b'0') as f64);
|
fraction += multiplier * ((current as u8 - b'0') as f64);
|
||||||
multiplier *= 0.1;
|
multiplier *= 0.1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -184,7 +184,7 @@ where
|
|||||||
|
|
||||||
// Parse exponent
|
// Parse exponent
|
||||||
if current != 'e' && current != 'E' {
|
if current != 'e' && current != 'E' {
|
||||||
return Ok((negative * (integer_part + fractional_part), Some(current)));
|
return Ok((negative * (result + fraction), Some(current)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let negative_exp = match iter.next() {
|
let negative_exp = match iter.next() {
|
||||||
@@ -198,7 +198,7 @@ where
|
|||||||
current = match iter.next() {
|
current = match iter.next() {
|
||||||
None => {
|
None => {
|
||||||
let pow = 10.0_f64.powf(negative_exp * exponent);
|
let pow = 10.0_f64.powf(negative_exp * exponent);
|
||||||
let to_ret = negative * (integer_part + fractional_part) * pow;
|
let to_ret = negative * ((result + fraction) * pow);
|
||||||
return Ok((to_ret, None));
|
return Ok((to_ret, None));
|
||||||
}
|
}
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
@@ -207,7 +207,7 @@ where
|
|||||||
exponent = exponent * 10.0 + ((current as u8 - b'0') as f64);
|
exponent = exponent * 10.0 + ((current as u8 - b'0') as f64);
|
||||||
} else {
|
} else {
|
||||||
let pow = 10.0_f64.powf(negative_exp * exponent);
|
let pow = 10.0_f64.powf(negative_exp * exponent);
|
||||||
let to_ret = negative * (integer_part + fractional_part) * pow;
|
let to_ret = negative * ((result + fraction) * pow);
|
||||||
return Ok((to_ret, Some(current)));
|
return Ok((to_ret, Some(current)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -893,6 +893,27 @@ mod test {
|
|||||||
assert_eq!(parsed.as_number(), -0.8);
|
assert_eq!(parsed.as_number(), -0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn borderline_example() {
|
||||||
|
let (parsed, remaining) = JsonValue::parse(&mut "-28.5175025263690110".chars()).unwrap();
|
||||||
|
assert_eq!(remaining, None);
|
||||||
|
let expected = -28.5175025263690110;
|
||||||
|
let actual = parsed.as_number();
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test fails due to float precision problems.
|
||||||
|
#[test]
|
||||||
|
fn borderline_example_2() {
|
||||||
|
let (parsed, remaining) = JsonValue::parse(&mut "62.33736768026505".chars()).unwrap();
|
||||||
|
assert_eq!(remaining, None);
|
||||||
|
let expected = 62.33736768026505;
|
||||||
|
let actual = parsed.as_number();
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn haversine_example() {
|
fn haversine_example() {
|
||||||
let s = include_str!("example.json");
|
let s = include_str!("example.json");
|
||||||
|
Reference in New Issue
Block a user