This repository has been archived by the owner on Sep 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from stevenroose/batching
Support JSON-RPC batching
- Loading branch information
Showing
4 changed files
with
210 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Rust JSON-RPC Library | ||
// Written in 2019 by | ||
// Andrew Poelstra <[email protected]> | ||
// | ||
// To the extent possible under law, the author(s) have dedicated all | ||
// copyright and related and neighboring rights to this software to | ||
// the public domain worldwide. This software is distributed without | ||
// any warranty. | ||
// | ||
// You should have received a copy of the CC0 Public Domain Dedication | ||
// along with this software. | ||
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. | ||
// | ||
|
||
use std::hash::{Hash, Hasher}; | ||
|
||
use serde_json::Value; | ||
|
||
/// Newtype around `Value` which allows hashing for use as hashmap keys | ||
/// This is needed for batch requests. | ||
/// | ||
/// The reason `Value` does not support `Hash` or `Eq` by itself | ||
/// is that it supports `f64` values; but for batch requests we | ||
/// will only be hashing the "id" field of the request/response | ||
/// pair, which should never need decimal precision and therefore | ||
/// never use `f64`. | ||
#[derive(Clone, PartialEq, Debug)] | ||
pub struct HashableValue<'a>(pub &'a Value); | ||
|
||
impl<'a> Eq for HashableValue<'a> {} | ||
|
||
impl<'a> Hash for HashableValue<'a> { | ||
fn hash<H: Hasher>(&self, state: &mut H) { | ||
match *self.0 { | ||
Value::Null => "null".hash(state), | ||
Value::Bool(false) => "false".hash(state), | ||
Value::Bool(true) => "true".hash(state), | ||
Value::Number(ref n) => { | ||
"number".hash(state); | ||
if let Some(n) = n.as_i64() { | ||
n.hash(state); | ||
} else if let Some(n) = n.as_u64() { | ||
n.hash(state); | ||
} else { | ||
n.to_string().hash(state); | ||
} | ||
}, | ||
Value::String(ref s) => { | ||
"string".hash(state); | ||
s.hash(state); | ||
}, | ||
Value::Array(ref v) => { | ||
"array".hash(state); | ||
v.len().hash(state); | ||
for obj in v { | ||
HashableValue(obj).hash(state); | ||
} | ||
}, | ||
Value::Object(ref m) => { | ||
"object".hash(state); | ||
m.len().hash(state); | ||
for (key, val) in m { | ||
key.hash(state); | ||
HashableValue(val).hash(state); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::collections::HashSet; | ||
use std::str::FromStr; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn hash_value() { | ||
let val = Value::from_str("null").unwrap(); | ||
let val = HashableValue(&val); | ||
|
||
let t = Value::from_str("true").unwrap(); | ||
let t = HashableValue(&t); | ||
|
||
let f = Value::from_str("false").unwrap(); | ||
let f = HashableValue(&f); | ||
|
||
let ns = Value::from_str("[0, -0, 123.4567, -100000000]").unwrap(); | ||
let ns = HashableValue(&ns); | ||
|
||
let m = Value::from_str("{ \"field\": 0, \"field\": -0 }").unwrap(); | ||
let m = HashableValue(&m); | ||
|
||
let mut coll = HashSet::new(); | ||
|
||
assert!(!coll.contains(&val)); | ||
coll.insert(val.clone()); | ||
assert!(coll.contains(&val)); | ||
|
||
assert!(!coll.contains(&t)); | ||
assert!(!coll.contains(&f)); | ||
coll.insert(t.clone()); | ||
assert!(coll.contains(&t)); | ||
assert!(!coll.contains(&f)); | ||
coll.insert(f.clone()); | ||
assert!(coll.contains(&t)); | ||
assert!(coll.contains(&f)); | ||
|
||
assert!(!coll.contains(&ns)); | ||
coll.insert(ns.clone()); | ||
assert!(coll.contains(&ns)); | ||
|
||
assert!(!coll.contains(&m)); | ||
coll.insert(m.clone()); | ||
assert!(coll.contains(&m)); | ||
} | ||
} | ||
|
||
|