Skip to main content

Live

Struct Live 

Source
pub struct Live { /* private fields */ }
Expand description

The repository a process reads, kept current.

Two forms, and the difference is whether anything is watched at all:

  • Live::pinned — one context, forever, at no cost. A command that answers and exits, a benchmark, a test: the picture cannot go stale inside them, and making them pay a stat per call to prove it would be a regression bought with nothing.
  • Live::watching — the shared server’s form. Every Live::current takes a Stamp first and rebuilds when it differs from the one the generation it holds was built at.
// the shared server follows the repository; a one-shot command does not
let followed = Live::watching(args, Arc::clone(&ctx));
let pinned = Live::pinned(ctx);
assert_eq!(pinned.generation(), followed.generation(), "both start at the first");

Implementations§

Source§

impl Live

Source

pub fn pinned(ctx: Arc<Context>) -> Live

One context that never changes: no stamp is taken and nothing is rebuilt.

let live = Live::pinned(Arc::clone(&ctx));
assert!(Arc::ptr_eq(&live.current(), &ctx), "the very context it was given");
Source

pub fn watching(args: RepoArgs, ctx: Arc<Context>) -> Live

A context that follows the repository, reloaded with args when git moves it.

args is how the process was pointed at the repository in the first place, kept so that a reload discovers the same root, the same distribution and the same discovery mode the first load did. Falls back to Live::pinned when the root is not a work tree: there is nothing to follow, and pretending otherwise would take a stamp over a handful of absent files on every request forever.

let live = Live::watching(args, ctx);
// the first reading is the one it was handed; a commit makes the next one the second
assert_eq!(live.view().generation, 0);
Source

pub fn generation(&self) -> u64

Which generation is current, without taking a stamp.

Only for a caller that already holds a View and wants to say which one it is; a caller that is about to use the context must take Live::view, because reading the number and then the context is two reads with a reload possible between them — the bug this whole module exists to end, one layer in. A projection memoised under the number read before the reload is the previous generation’s, handed out as the current one.

let live = Live::pinned(ctx);
assert_eq!(live.generation(), live.view().generation);
Source

pub fn current(&self) -> Arc<Context> ⓘ

The context as it is now: the one that was loaded, or a newly built one when the repository has moved under this process.

let live = Live::pinned(ctx);
assert!(Arc::ptr_eq(&live.current(), &live.view().ctx));
Source

pub fn view(&self) -> View

The current generation and the context of it, as one reading.

One call, so that a caller keying a memo on the number and filling it from the context cannot key the new context under the old number.

let live = Live::pinned(ctx);
let memo: Memo<usize> = Memo::default();
// the shape every projection uses: one reading, keyed and filled from itself
let view = live.view();
let objects = memo.get_or_init(view.generation, || view.ctx.index.objects.len());
assert_eq!(*objects, view.ctx.index.objects.len());
Source

pub fn view_without_waiting(self: &Arc<Self>) -> (View, bool)

The generation there is, at once, and whether the repository has moved past it: what a page a person is looking at asks for (ADR 0142).

Live::view waits for a reload, because an answer must be of the repository the caller saw. A page need not be: it is drawn from the generation that exists, says that the repository changed, and is read again once the new generation has loaded. So when the repository has moved, this starts the reload on a thread of its own, unless one is already running, and returns the existing generation with behind set. Nothing about Live::view changes for any other caller.

use majordomus_cli::live::Live;
use majordomus_cli::synthetic::SyntheticRepository;
use std::sync::Arc;

let repo = SyntheticRepository::small().unwrap();
let live = Arc::new(Live::pinned(repo.context().unwrap()));
// a pinned view follows nothing, so the generation there is is the one to show and
// the repository has never moved past it
let (view, behind) = live.view_without_waiting();
assert!(!behind);
assert_eq!(view.generation, live.view().generation);

Trait Implementations§

Source§

impl Debug for Live

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Live

§

impl !RefUnwindSafe for Live

§

impl !UnwindSafe for Live

§

impl Send for Live

§

impl Sync for Live

§

impl Unpin for Live

§

impl UnsafeUnpin for Live

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more