-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flesh out the slice API for the user code #9
Changes from all commits
0100d22
8b595df
fa76297
045b1e9
6a1febf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,11 @@ | ||
#![doc = include_str!("../README.md")] | ||
|
||
use std::{ | ||
fmt::{self, Display, Write}, | ||
num::Wrapping, | ||
ops::Range, | ||
}; | ||
|
||
pub mod effect; | ||
pub mod entity; | ||
pub mod entity_manager; | ||
|
@@ -16,6 +22,23 @@ pub struct PersistenceId { | |
pub entity_id: EntityId, | ||
} | ||
|
||
impl PersistenceId { | ||
pub fn new(entity_type: EntityType, entity_id: EntityId) -> Self { | ||
Self { | ||
entity_type, | ||
entity_id, | ||
} | ||
} | ||
} | ||
|
||
impl Display for PersistenceId { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.write_str(&self.entity_type)?; | ||
f.write_char('|')?; | ||
f.write_str(&self.entity_id) | ||
} | ||
} | ||
|
||
/// A message encapsulates a command that is addressed to a specific entity. | ||
#[derive(Debug, PartialEq)] | ||
pub struct Message<C> { | ||
|
@@ -34,3 +57,77 @@ impl<C> Message<C> { | |
} | ||
} | ||
} | ||
|
||
/// A slice is deterministically defined based on the persistence id. | ||
/// `numberOfSlices` is not configurable because changing the value would result in | ||
/// different slice for a persistence id than what was used before, which would | ||
/// result in invalid events_by_slices call on a source provider. | ||
pub const NUMBER_OF_SLICES: u32 = 1024; | ||
|
||
/// A slice is deterministically defined based on the persistence id. The purpose is to | ||
/// evenly distribute all persistence ids over the slices and be able to query the | ||
/// events for a range of slices. | ||
pub fn slice_for_persistence_id(persistence_id: &PersistenceId) -> u32 { | ||
(jdk_string_hashcode(&persistence_id.to_string()) % NUMBER_OF_SLICES as i32).unsigned_abs() | ||
} | ||
|
||
/// Split the total number of slices into ranges by the given `number_of_ranges`. | ||
/// For example, `NUMBER_OF_SLICES` is 1024 and given 4 `number_of_ranges` this method will | ||
/// return ranges (0 to 255), (256 to 511), (512 to 767) and (768 to 1023). | ||
pub fn slice_ranges(number_of_ranges: u32) -> Vec<Range<u32>> { | ||
let range_size = NUMBER_OF_SLICES / number_of_ranges; | ||
assert!( | ||
number_of_ranges * range_size == NUMBER_OF_SLICES, | ||
"number_of_ranges must be a whole number divisor of numberOfSlices." | ||
); | ||
let mut ranges = Vec::with_capacity(number_of_ranges as usize); | ||
for i in 0..number_of_ranges { | ||
ranges.push(i * range_size..i * range_size + range_size) | ||
} | ||
ranges | ||
} | ||
|
||
// Implementation of the JDK8 string hashcode: | ||
// https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#hashCode | ||
fn jdk_string_hashcode(s: &str) -> i32 { | ||
let mut hash = Wrapping(0i32); | ||
const MULTIPLIER: Wrapping<i32> = Wrapping(31); | ||
let count = s.len(); | ||
if count > 0 { | ||
let mut chars = s.chars(); | ||
for _ in 0..count { | ||
hash = hash * MULTIPLIER + Wrapping(chars.next().unwrap() as i32); | ||
} | ||
} | ||
hash.0 | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use smol_str::SmolStr; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_jdk_string_hashcode() { | ||
assert_eq!(jdk_string_hashcode(""), 0); | ||
assert_eq!(jdk_string_hashcode("howtodoinjava.com"), 1894145264); | ||
assert_eq!(jdk_string_hashcode("hello world"), 1794106052); | ||
} | ||
|
||
#[test] | ||
fn test_slice_for_persistence_id() { | ||
assert_eq!( | ||
slice_for_persistence_id(&PersistenceId::new( | ||
SmolStr::from("some-entity-type"), | ||
SmolStr::from("some-entity-id") | ||
)), | ||
451 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have verified that it's the same slice in jvm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excellent! |
||
); | ||
} | ||
|
||
#[test] | ||
fn test_slice_ranges() { | ||
assert_eq!(slice_ranges(4), vec![0..256, 256..512, 512..768, 768..1024]); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These were taken from a JDK example.