profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/jeffa5/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

automerge/automerge 11194

A JSON-like data structure (a CRDT) that can be modified concurrently by different users, and merged again automatically.

automerge/automerge-rs 371

Rust implementation of automerge

jeffa5/block-breaker 1

A block breaker library written in Rust

jeffa5/mirage-raft 1

A raft implementation for mirage

jeffa5/aoc-19 0

Advent of code 2019

jeffa5/automerge 0

A JSON-like data structure (a CRDT) that can be modified concurrently by different users, and merged again automatically.

jeffa5/automerge-graphviz 0

A graphviz viewer for automerge change hash graphs

push eventjeffa5/automerge-rs

Andrew Jeffery

commit sha dfe6922e7cf89e154b5a0fe5229872e46f8f5614

Re-enable one cli integration test

view details

push time in 2 days

create barnchjeffa5/automerge-rs

branch : github-actions

created branch time in 2 days

Pull request review commentautomerge/automerge-rs

Add initial github actions setup

 use std::env;  use duct::cmd; -#[test]-fn import_stdin() {-    let bin = env!("CARGO_BIN_EXE_automerge");-    let initial_state_json = serde_json::json!({-        "birds": {-            "wrens": 3.0,-            "sparrows": 15.0-        }-    });-    let json_bytes = serde_json::to_string_pretty(&initial_state_json).unwrap();+// #[test]

I never saw them complete, despite being about 20mins. Also gives some weird output, e.g. here: https://github.com/automerge/automerge-rs/runs/3603850245?check_suite_focus=true

jeffa5

comment created time in 9 days

PullRequestReviewEvent

Pull request review commentautomerge/automerge-rs

Add initial github actions setup

 use std::env;  use duct::cmd; -#[test]-fn import_stdin() {-    let bin = env!("CARGO_BIN_EXE_automerge");-    let initial_state_json = serde_json::json!({-        "birds": {-            "wrens": 3.0,-            "sparrows": 15.0-        }-    });-    let json_bytes = serde_json::to_string_pretty(&initial_state_json).unwrap();+// #[test]

These were causing the new CI to take a very long time. I haven't diagnosed the issue but personally I'm not sure it should block moving away from Travis at the moment.

jeffa5

comment created time in 10 days

PullRequestReviewEvent

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 33185d9d6c2c75abe226d2ed19346d155dbd3ce0

Only run on things targetting main

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha c730a7fb3a1e00bdaa2682d9ca17b35deaa26674

Tidy up wasm testing

view details

Andrew Jeffery

commit sha 96571e9a6f6bbef40e369ae114e73081aba5ee0f

Separate out clippy

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 3d7f82eb4695fc7c80f4a70f36c05b13fe8d5ef4

Actually, just specify the dependency path

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 502211ed92f8699d37681e971dae876f86789a91

Remove caching yarn

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 3622ec5fdebe1f5f7c5263c36fd29d01ffa668bd

Remove old travis

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 4d0a289de6b799e2201d260061b8af25eaa36df5

Split to multiple jobs

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha e8a6a8c1293b33cf7653377936e34292deec6a58

Hide test

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 73f7b8591c6d6b85767e91bc4e6fef7ec381e386

Revert "Hide test that has weird CI behaviour" This reverts commit 717080e42b7cd9fa9c4f83284df9095d672bd8b1.

view details

Andrew Jeffery

commit sha 365b21b9d238ba15d4ac13685f9eba013b3dacdf

Hide failing test in CI

view details

push time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 717080e42b7cd9fa9c4f83284df9095d672bd8b1

Hide test that has weird CI behaviour

view details

push time in 10 days

issue commentprometheus-community/helm-charts

[prometheus-blackbox-exporter] serviceMonitor.enabled doesn't include a ServiceMonitor for the exporter itself

Yes, I do. The CRD for ServiceMonitor exists but it just doesn't create one.

jeffa5

comment created time in 10 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 94769e2daeeb32a6fccdb0ffd27aaa1d2a488f41

Sequence tree (#236) Switch from im_rc to `SequenceTree`

view details

Andrew Jeffery

commit sha cf9e47eb5880346588c661c1cd97558ca3e55bb6

Add initial github actions setup

view details

Andrew Jeffery

commit sha 69736437b2d00043fe0ef630430405e562fbbde3

Add more steps

view details

Andrew Jeffery

commit sha 6ed45ce6273229461c6d97264e9302de66e14028

Add names

view details

Andrew Jeffery

commit sha 5984a537d60a86b4b09eb0cb1d5c8ef51b5849ea

Try caching

view details

Andrew Jeffery

commit sha 142657b01bf4b5c9b4f4ba11267a190932808be3

Reduce proptest size

view details

push time in 11 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 11b234925d6f4cc6120127678d01e12d641b5e0c

Add names

view details

Andrew Jeffery

commit sha a66ff71cd63c51aadf8133d8753611b8e8c88e21

Try caching

view details

push time in 11 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 30075e649dab7d80758923cee54ac2ac02e43110

Add more steps

view details

push time in 11 days

PR opened automerge/automerge-rs

Add initial github actions setup
+42 -0

0 comment

1 changed file

pr created time in 11 days

create barnchautomerge/automerge-rs

branch : github-actions

created branch time in 11 days

delete branch automerge/automerge-rs

delete branch : sequence-tree

delete time in 11 days

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha f9a300c23dd323555d71207c7d8a60e250ea7d51

Tidy up root insert

view details

Andrew Jeffery

commit sha 0dcd3b628bd1a0ce23bec6d7bf11f11aadb4a318

Tidy up set to remove mut index

view details

Andrew Jeffery

commit sha 1afeb1a30c885e15eb21f03dd4bf5c4d7b652330

Remove mut index

view details

push time in 12 days

Pull request review commentautomerge/automerge-rs

Sequence tree

+use std::{+    cmp::{min, Ordering},+    fmt::Debug,+    mem,+};++use automerge_protocol::OpId;++pub type SequenceTree<T> = SequenceTreeInternal<T, 25>;++#[derive(Clone, Debug)]+pub struct SequenceTreeInternal<T, const B: usize> {+    root_node: Option<SequenceTreeNode<T, B>>,+}++#[derive(Clone, Debug, PartialEq)]+struct SequenceTreeNode<T, const B: usize> {+    elements: Vec<Box<(OpId, T)>>,+    children: Vec<SequenceTreeNode<T, B>>,+    length: usize,+}++impl<T, const B: usize> SequenceTreeInternal<T, B>+where+    T: Clone + Debug,+{+    pub fn new() -> Self {+        Self { root_node: None }+    }++    pub fn len(&self) -> usize {+        self.root_node.as_ref().map_or(0, |n| n.len())+    }++    pub fn is_empty(&self) -> bool {+        self.len() == 0+    }++    pub fn iter(&self) -> Iter<'_, T, B> {+        Iter {+            inner: self,+            index: 0,+        }+    }++    pub fn insert(&mut self, mut index: usize, opid: OpId, element: T) {+        let old_len = self.len();+        if let Some(root) = self.root_node.as_mut() {+            #[cfg(debug_assertions)]+            root.check();++            if root.is_full() {+                let original_len = root.len();+                let new_root = SequenceTreeNode::new();++                // move new_root to root position+                let old_root = mem::replace(root, new_root);++                root.length += old_root.len();+                root.children.push(old_root);+                root.split_child(0);++                // after splitting the root has one element and two children, find which child the+                // index is in+                let mut i = 0;+                if root.children[0].len() < index {+                    i += 1;+                    index -= root.children[0].len() + 1+                }+                assert_eq!(original_len, root.len());+                root.length += 1;+                root.children[i].insert_into_non_full_node(index, opid, element)+            } else {+                root.insert_into_non_full_node(index, opid, element)+            }+        } else {+            self.root_node = Some(SequenceTreeNode {+                elements: vec![Box::new((opid, element))],+                children: Vec::new(),+                length: 1,+            })+        }+        assert_eq!(self.len(), old_len + 1, "{:#?}", self);+    }++    pub fn push_back(&mut self, opid: OpId, element: T) {+        let l = self.len();+        self.insert(l, opid, element)+    }++    pub fn get(&self, index: usize) -> Option<(OpId, &T)> {+        self.root_node.as_ref().and_then(|n| n.get(index))+    }++    pub fn get_mut(&mut self, index: usize) -> Option<(OpId, &mut T)> {+        self.root_node.as_mut().and_then(|n| n.get_mut(index))+    }++    pub fn remove(&mut self, index: usize) -> T {+        if let Some(root) = self.root_node.as_mut() {+            #[cfg(debug_assertions)]+            let len = root.check();+            let old = root.remove(index);++            if root.elements.is_empty() {+                if root.is_leaf() {+                    self.root_node = None;+                } else {+                    self.root_node = Some(root.children.remove(0));+                }+            }++            #[cfg(debug_assertions)]+            debug_assert_eq!(len, self.root_node.as_ref().map_or(0, |r| r.check()) + 1);+            old.1+        } else {+            panic!("remove from empty tree")+        }+    }++    pub fn set(&mut self, index: usize, element: T) -> T {+        self.root_node.as_mut().unwrap().set(index, element)+    }+}++impl<T, const B: usize> SequenceTreeNode<T, B>+where+    T: Clone + Debug,+{+    fn new() -> Self {+        Self {+            elements: Vec::new(),+            children: Vec::new(),+            length: 0,+        }+    }++    pub fn len(&self) -> usize {+        self.length+    }++    fn is_leaf(&self) -> bool {+        self.children.is_empty()+    }++    fn is_full(&self) -> bool {+        self.elements.len() >= 2 * B - 1+    }++    fn insert_into_non_full_node(&mut self, index: usize, opid: OpId, element: T) {+        assert!(!self.is_full());+        if self.is_leaf() {+            self.length += 1;+            self.elements.insert(index, Box::new((opid, element)));+        } else {+            let mut cumulative_len = 0;+            for (child_index, child) in self.children.iter_mut().enumerate() {+                if cumulative_len + child.len() >= index {+                    if child.is_full() {+                        self.split_child(child_index);++                        let mut cumulative_len = 0;+                        for child in self.children.iter_mut() {+                            if cumulative_len + child.len() >= index {+                                child.insert_into_non_full_node(+                                    index - cumulative_len,+                                    opid,+                                    element,+                                );+                                self.length += 1;+                                break;+                            } else {+                                cumulative_len += child.len() + 1;

I've had a little refactor and tried having a cumulative_iterator function but the borrow-checker gets in the way as it borrows the entire struct rather than just the field. Something I'll leave for another time I think.

jeffa5

comment created time in 12 days

PullRequestReviewEvent

push eventautomerge/automerge-rs

Andrew Jeffery

commit sha 3ef9daab9f359941763221508965f6b3e8cefacf

Document public functions and rename push_back to push

view details

Andrew Jeffery

commit sha 9581900ee84b0310ba518b9249715a77f1bd3c52

Tidy up insert_into_non_full_node

view details

push time in 12 days

Pull request review commentautomerge/automerge-rs

Sequence tree

+use std::{+    cmp::{min, Ordering},+    fmt::Debug,+    mem,+};++use automerge_protocol::OpId;++pub type SequenceTree<T> = SequenceTreeInternal<T, 25>;++#[derive(Clone, Debug)]+pub struct SequenceTreeInternal<T, const B: usize> {+    root_node: Option<SequenceTreeNode<T, B>>,+}++#[derive(Clone, Debug, PartialEq)]+struct SequenceTreeNode<T, const B: usize> {+    elements: Vec<Box<(OpId, T)>>,+    children: Vec<SequenceTreeNode<T, B>>,+    length: usize,+}++impl<T, const B: usize> SequenceTreeInternal<T, B>+where+    T: Clone + Debug,+{+    pub fn new() -> Self {+        Self { root_node: None }+    }++    pub fn len(&self) -> usize {+        self.root_node.as_ref().map_or(0, |n| n.len())+    }++    pub fn is_empty(&self) -> bool {+        self.len() == 0+    }++    pub fn iter(&self) -> Iter<'_, T, B> {+        Iter {+            inner: self,+            index: 0,+        }+    }++    pub fn insert(&mut self, mut index: usize, opid: OpId, element: T) {+        let old_len = self.len();+        if let Some(root) = self.root_node.as_mut() {+            #[cfg(debug_assertions)]+            root.check();++            if root.is_full() {+                let original_len = root.len();+                let new_root = SequenceTreeNode::new();++                // move new_root to root position+                let old_root = mem::replace(root, new_root);++                root.length += old_root.len();+                root.children.push(old_root);+                root.split_child(0);++                // after splitting the root has one element and two children, find which child the+                // index is in+                let mut i = 0;+                if root.children[0].len() < index {+                    i += 1;+                    index -= root.children[0].len() + 1+                }+                assert_eq!(original_len, root.len());+                root.length += 1;+                root.children[i].insert_into_non_full_node(index, opid, element)+            } else {+                root.insert_into_non_full_node(index, opid, element)+            }+        } else {+            self.root_node = Some(SequenceTreeNode {+                elements: vec![Box::new((opid, element))],+                children: Vec::new(),+                length: 1,+            })+        }+        assert_eq!(self.len(), old_len + 1, "{:#?}", self);+    }++    pub fn push_back(&mut self, opid: OpId, element: T) {+        let l = self.len();+        self.insert(l, opid, element)+    }++    pub fn get(&self, index: usize) -> Option<(OpId, &T)> {+        self.root_node.as_ref().and_then(|n| n.get(index))+    }++    pub fn get_mut(&mut self, index: usize) -> Option<(OpId, &mut T)> {+        self.root_node.as_mut().and_then(|n| n.get_mut(index))+    }++    pub fn remove(&mut self, index: usize) -> T {+        if let Some(root) = self.root_node.as_mut() {+            #[cfg(debug_assertions)]+            let len = root.check();+            let old = root.remove(index);++            if root.elements.is_empty() {+                if root.is_leaf() {+                    self.root_node = None;+                } else {+                    self.root_node = Some(root.children.remove(0));+                }+            }++            #[cfg(debug_assertions)]+            debug_assert_eq!(len, self.root_node.as_ref().map_or(0, |r| r.check()) + 1);+            old.1+        } else {+            panic!("remove from empty tree")

I've tried to follow a similar API to Vec, which doesn't return an option but panics if you access an element outside of the range. Since this is an internal datastructure (for now) I think it is ok to panic, will document it though.

jeffa5

comment created time in 12 days

PullRequestReviewEvent

pull request commentautomerge/automerge-rs

Sequence tree

Very cool. And sequencetree is a great name for this structure.

It might be a terrible time to mention this but I'd be happy to pull my tree out into its own crate for reuse. (I've been thinking about doing that for awhile anyway). Its fully tested now and I'm quite happy with its performance, though it still uses a bit more unsafe than I'd like.

I think that would be great! More reusable data structures like this make it all easier in the long run and can always be updated given some level of compatibility :)

jeffa5

comment created time in 12 days