Skip to content

Commit 9b107f8

Browse files
committed
Better testing
1 parent 6cff1a2 commit 9b107f8

File tree

11 files changed

+349
-190
lines changed

11 files changed

+349
-190
lines changed

.github/workflows/rust.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Continuous integration
2+
3+
on: [push, pull_request]
4+
5+
env:
6+
CARGO_TERM_COLOR: always
7+
8+
jobs:
9+
ci:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
rust: [stable]
14+
15+
steps:
16+
- name: Checkout source code
17+
uses: actions/checkout@v2
18+
19+
- name: Build
20+
run: cargo build
21+
22+
- name: Test
23+
run: cargo test

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ with more fine-grained access tracking. To use it, we can just:
5858
- Wrap the `files` argument in comemo's `Tracked` container.
5959

6060
This instructs comemo to memoize the evaluation and to automatically track all
61-
file accesses during a memoization call. As a result, we can reuse the result of
62-
a `.calc` script evaluation as as long as its dependencies stay the same—even
63-
if other files change.
61+
file accesses during a memoized call. As a result, we can reuse the result of a
62+
`.calc` script evaluation as as long as its dependencies stay the same—even if
63+
other files change.
6464

6565
```rust
6666
use comemo::{memoize, track, Tracked};
@@ -82,7 +82,7 @@ impl Files {
8282

8383
For the full example see [`examples/calc.rs`][calc].
8484

85-
[calc]: (https://github.com/typst/comemo/blob/main/examples/calc.rs)
85+
[calc]: https://github.com/typst/comemo/blob/main/examples/calc.rs
8686

8787
## License
8888
This crate is dual-licensed under the MIT and Apache 2.0 licenses.

examples/calc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use comemo::{memoize, track, Track, Tracked};
99

1010
fn main() {
1111
// Create some scripts in the calc language. This language supports addition
12-
// and `eval` statements refering to other files.
12+
// and `eval` statements referring to other files.
1313
let mut files = Files(HashMap::new());
1414
files.write("alpha.calc", "2 + eval beta.calc");
1515
files.write("beta.calc", "2 + 3");
@@ -19,7 +19,7 @@ fn main() {
1919
assert_eq!(evaluate("eval alpha.calc", files.track()), 7);
2020

2121
// [Miss] This is not a top-level hit because this exact string was never
22-
// passed to `evalaute`, but this does not compute "2 + 3" again.
22+
// passed to `evaluate`, but this does not compute "2 + 3" again.
2323
assert_eq!(evaluate("eval beta.calc", files.track()), 5);
2424

2525
// Modify the gamma file.

macros/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use syn::{parse_quote, Error, Result};
5454
/// There are certain restrictions that apply to memoized functions. Most of
5555
/// these are checked by comemo, but some are your responsibility:
5656
/// - They must be **pure**, that is, **free of observable side effects**. This
57-
/// is **your reponsibility** as comemo can't check it.
57+
/// is **your responsibility** as comemo can't check it.
5858
/// - They must have an explicit return type.
5959
/// - They cannot have mutable parameters (conflicts with purity).
6060
/// - They cannot use destructuring patterns in their arguments.
@@ -68,7 +68,7 @@ pub fn memoize(_: BoundaryStream, stream: BoundaryStream) -> BoundaryStream {
6868

6969
/// Make a type trackable.
7070
///
71-
/// Adding this to an impl block of a type `T`, implements the `Track` trait for
71+
/// Adding this to an impl block of a type `T` implements the `Track` trait for
7272
/// `T`. This lets you call `.track()` on that type, producing a `Tracked<T>`.
7373
/// When such a tracked type is used an argument to a memoized function it
7474
/// enjoys fine-grained access tracking instead of being bluntly hashed.
@@ -102,8 +102,11 @@ pub fn memoize(_: BoundaryStream, stream: BoundaryStream) -> BoundaryStream {
102102
/// methods. Just like with memoized functions, certain restrictions apply to
103103
/// tracked methods:
104104
/// - They must be **pure**, that is, **free of observable side effects**. This
105-
/// is **your reponsibility** as comemo can't check it. You can use interior
105+
/// is **your responsibility** as comemo can't check it. You can use interior
106106
/// mutability as long as the method stays idempotent.
107+
/// - Their **return values must implement `Hash`** and **must feed all the
108+
/// information they expose to the hasher**. Otherwise, memoized results might
109+
/// get reused invalidly.
107110
/// - They cannot be generic.
108111
/// - They can only be private or public not `pub(...)`.
109112
/// - They cannot be `unsafe`, `async` or `const`.

src/cache.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,38 @@ where
3434
let constraint = In::Constraint::default();
3535

3636
// Check if there is a cached output.
37-
if let Some(constrained) = cache.borrow_mut().lookup::<In, Out>(key, &input) {
37+
let mut borrow = cache.borrow_mut();
38+
if let Some(constrained) = borrow.lookup::<In, Out>(key, &input) {
3839
// Add the cached constraints to the outer ones.
3940
let (_, outer) = input.retrack(&constraint);
4041
outer.join(&constrained.constraint);
41-
return constrained.output.clone();
42+
let value = constrained.output.clone();
43+
borrow.last_was_hit = true;
44+
return value;
4245
}
4346

4447
// Execute the function with the new constraints hooked in.
48+
drop(borrow);
4549
let (input, outer) = input.retrack(&constraint);
4650
let output = func(input);
4751

4852
// Add the new constraints to the outer ones.
4953
outer.join(&constraint);
5054

5155
// Insert the result into the cache.
52-
cache.borrow_mut().insert::<In, Out>(key, constraint, output.clone());
56+
borrow = cache.borrow_mut();
57+
borrow.insert::<In, Out>(key, constraint, output.clone());
58+
borrow.last_was_hit = false;
5359

5460
output
5561
})
5662
}
5763

64+
/// Whether the last call was a hit.
65+
pub fn last_was_hit() -> bool {
66+
CACHE.with(|cache| cache.borrow().last_was_hit)
67+
}
68+
5869
/// Evict the cache.
5970
///
6071
/// This removes all memoized results from the cache whose age is larger than or
@@ -82,6 +93,8 @@ pub fn evict(max_age: usize) {
8293
struct Cache {
8394
/// Maps from function IDs + hashes to memoized results.
8495
map: HashMap<(TypeId, u128), Vec<Entry>>,
96+
/// Whether the last call was a hit.
97+
last_was_hit: bool,
8598
}
8699

87100
impl Cache {

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ This is where comemo comes into play. It implements _constrained memoization_
4949
with more fine-grained access tracking. To use it, we can just:
5050
5151
- Add the [`#[memoize]`](macro@memoize) attribute to the `evaluate` function.
52-
- Add the [`#[track]`](macro@memoize) attribute to the impl block of `Files`.
52+
- Add the [`#[track]`](macro@track) attribute to the impl block of `Files`.
5353
- Wrap the `files` argument in comemo's [`Tracked`] container.
5454
5555
This instructs comemo to memoize the evaluation and to automatically track all
56-
file accesses during a memoization call. As a result, we can reuse the result of
57-
a `.calc` script evaluation as as long as its dependencies stay the same—even
58-
if other files change.
56+
file accesses during a memoized call. As a result, we can reuse the result of a
57+
`.calc` script evaluation as as long as its dependencies stay the same—even if
58+
other files change.
5959
6060
```
6161
# /*
@@ -79,7 +79,7 @@ impl Files {
7979
8080
For the full example see [`examples/calc.rs`][calc].
8181
82-
[calc]: (https://github.com/typst/comemo/blob/main/examples/calc.rs)
82+
[calc]: https://github.com/typst/comemo/blob/main/examples/calc.rs
8383
*/
8484

8585
mod cache;
@@ -96,7 +96,7 @@ pub use comemo_macros::{memoize, track};
9696
/// These are implementation details. Do not rely on them!
9797
#[doc(hidden)]
9898
pub mod internal {
99-
pub use crate::cache::memoized;
99+
pub use crate::cache::{last_was_hit, memoized};
100100
pub use crate::constraint::{hash, Join, MultiConstraint, SoloConstraint};
101101
pub use crate::input::{assert_hashable_or_trackable, Args};
102102
pub use crate::track::{to_parts, Trackable};

src/prehashed.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use siphasher::sip128::{Hasher128, SipHasher};
2323
/// hash collision is reduced to an absolute minimum. Therefore, this type
2424
/// additionally provides `PartialEq` and `Eq` implementations that compare by
2525
/// hash instead of by value. For this to be correct, your hash implementation
26-
/// **must feed all information relevant to the `PartialEq` impl to the hasher.**
26+
/// **must feed all information relevant to the `PartialEq` impl to the
27+
/// hasher.**
2728
#[derive(Copy, Clone)]
2829
pub struct Prehashed<T: ?Sized> {
2930
/// The precomputed hash.

src/track.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use crate::internal::Family;
66

77
/// A trackable type.
88
///
9-
/// This is implemented by types that have an implementation block annoted with
10-
/// `#[track]` and for trait objects whose traits are annotated with `#[track]`.
11-
/// For more details, see [its documentation](macro@crate::track).
9+
/// This is implemented by types that have an implementation block annotated
10+
/// with `#[track]` and for trait objects whose traits are annotated with
11+
/// `#[track]`. For more details, see [its documentation](macro@crate::track).
1212
pub trait Track: Trackable {
1313
/// Start tracking a value.
1414
#[inline]

tests/evict.rs

Lines changed: 0 additions & 25 deletions
This file was deleted.

tests/kinds.rs

Lines changed: 0 additions & 143 deletions
This file was deleted.

0 commit comments

Comments
 (0)