1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! ### Which `Easy*` is for me?
//!
//! * Use `Easy*Exclusive` when the underlying `Repository` eventually needs mutation, for instance to update data structures
//!    - This is useful for long-running applications that eventually need to adapt to changes in the repository and pick up
//!      new packs after a GC operation or a received pack.
//! * Use the non-exclusive variants if the `Repository` doesn't ever have to change, for example as in one-off commands.
//!
//! ### Implementation Notes
//!
//! - Why no `Easy` with simply an owned `Repository`, instead `Rc<Repository>` is enforced
//!    - When this is desired, rather use `EasyShared` and drop the `EasyShared` once mutable access to the `Repository` is needed.
//!      `Access` is not usable for functions that require official `&mut` mutability, it's made for interior mutability to support
//!       trees of objects.
use std::{
    cell::RefCell,
    ops::{Deref, DerefMut},
    sync::Arc,
    time::SystemTime,
};

use git_hash::ObjectId;
use git_object as objs;
use git_odb as odb;
use git_ref as refs;

use crate::Repository;

mod impls;

pub(crate) mod ext;

pub mod borrow;
pub mod object;
mod oid;
pub mod reference;
pub mod state;

/// An [ObjectId] with access to a repository.
#[derive(Eq, Hash, Ord, PartialOrd, Clone, Copy)]
pub struct Oid<'r, A> {
    id: ObjectId,
    access: &'r A,
}

/// A decoded object with a reference to its owning repository.
///
/// ## Limitations
///
/// Note that it holds a reference to a buffer of it's associated repository handle, so there
/// can only be one at a time, per handle.
pub struct ObjectRef<'repo, A> {
    /// The id of the object
    pub id: ObjectId,
    /// The kind of the object
    pub kind: objs::Kind,
    /// The fully decoded object data
    pub data: std::cell::Ref<'repo, [u8]>,
    access: &'repo A,
}

/// A decoded tree object with access to its owning repository.
///
/// Please note that the limitations described in [ObjectRef] apply here as well.
pub struct TreeRef<'repo, A> {
    /// The id of the tree
    pub id: ObjectId,
    /// The fully decoded tree data
    pub data: std::cell::Ref<'repo, [u8]>,
    access: &'repo A,
}

/// A detached, self-contained object, without access to its source repository.
///
/// Use it if an `ObjectRef` should be sent over thread boundaries or stored in collections.
#[derive(Clone)]
pub struct Object {
    /// The id of the object
    pub id: ObjectId,
    /// The kind of the object
    pub kind: objs::Kind,
    /// The fully decoded object data
    pub data: Vec<u8>,
}

/// A reference that points to an object or reference, with access to its source repository.
pub struct Reference<'r, A> {
    pub(crate) backing: Option<reference::Backing>,
    pub(crate) access: &'r A,
}

#[cfg(not(feature = "local"))]
type PackCache = odb::pack::cache::Never;
#[cfg(feature = "local")]
type PackCache = odb::pack::cache::lru::StaticLinkedList<64>;

#[derive(Default)]
struct ModifieablePackedRefsBuffer {
    packed_refs: Option<refs::packed::Buffer>,
    modified: Option<SystemTime>,
}

/// State for use in `Easy*` to provide mutable parts of a repository such as caches and buffers.
#[derive(Default)]
pub struct State {
    /// As the packed-buffer may hold onto a memory map, we avoid that to exist once per thread, multiplying system resources.
    /// This seems worth the cost of always going through an `Arc<RwLock<…>>>`. Note that `EasyArcExclusive` uses the same construct
    /// but the reason we make this distinction at all is that there are other easy's that allows to chose exactly what you need in
    /// your application. `State` is one size fits all with supporting single-threaded applications only.
    packed_refs: Arc<parking_lot::RwLock<ModifieablePackedRefsBuffer>>,
    pack_cache: RefCell<PackCache>,
    buf: RefCell<Vec<u8>>,
}

/// A utility trait to represent access to a repository.
///
/// It provides immutable and possibly mutable access. Both types of access are validated at runtime, which may fail
/// or may block, depending on the implementation.
///
/// Furthermore it provides access to additional state for use with the [`Repository`]. It is designed for thread-local
/// mutable access, which is checked at runtime as well. This means that operations can't freely be interleaved and some
/// care as to be taken especially in conjunction with [`ObjectRef`] instances.
pub trait Access {
    /// The type of a shared borrow to the Repository
    type RepoRef: Deref<Target = Repository>;
    // TODO: Once GATs become stable, try to use them to make it work with RefCells too, aka EasyExclusive
    /// The type of a mutable borrow to the Repository
    type RepoRefMut: DerefMut<Target = Repository>;

    /// Return a shared borrow to the repository.
    ///
    /// This may fail if there already is a mutable borrow
    fn repo(&self) -> borrow::repo::Result<Self::RepoRef>;

    /// Returns a mutable borrow to the repository if possible.
    ///
    /// # NOTE
    ///
    /// This may not be supported by all implementations. Choosing an implementation that does support it is particularly
    /// relevant for long-running applications that make changes to the repository.
    fn repo_mut(&self) -> borrow::repo::Result<Self::RepoRefMut>;

    /// Return a shared borrow of the repository state, with support for interior mutability.
    fn state(&self) -> &State;
}