git_bug/replica/entity/id/
entity_id.rs

1// git-bug-rs - A rust library for interfacing with git-bug repositories
2//
3// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
4// SPDX-License-Identifier: GPL-3.0-or-later
5//
6// This file is part of git-bug-rs/git-gub.
7//
8// You should have received a copy of the License along with this program.
9// If not, see <https://www.gnu.org/licenses/agpl.txt>.
10
11//! [`Ids`][`Id`] connect with their respective [`Entity`].
12
13use std::{fmt::Display, marker::PhantomData};
14
15use serde::{Deserialize, Serialize};
16
17use super::Id;
18use crate::replica::entity::Entity;
19
20/// An [`Id`] that is scoped to an [`Entity`].
21///
22/// This is useful, as it allows limiting the semantic meaning of an [`Id`].
23/// As such it can be used to maintain provenance information of [`Ids`][`Id`].
24///
25/// # Note
26/// The only safe way to obtain a [`EntityId`] is via the
27/// [`Replica::get_*`][`crate::replica::Replica::get`] functions.
28// As explained in the toplevel doc comment, this Derive is only a implementation detail.
29#[allow(clippy::unsafe_derive_deserialize)]
30#[derive(Debug, Deserialize, Serialize)]
31pub struct EntityId<E: Entity>(Id, PhantomData<E>);
32
33impl<E: Entity> PartialEq for EntityId<E> {
34    fn eq(&self, other: &Self) -> bool {
35        self.0 == other.0
36    }
37}
38
39impl<E: Entity> Ord for EntityId<E> {
40    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
41        self.0.cmp(&other.0)
42    }
43}
44
45impl<E: Entity> PartialOrd for EntityId<E> {
46    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
47        Some(self.cmp(other))
48    }
49}
50
51impl<E: Entity> Eq for EntityId<E> {}
52
53impl<E: Entity> Copy for EntityId<E> {}
54
55impl<E: Entity> Clone for EntityId<E> {
56    fn clone(&self) -> Self {
57        *self
58    }
59}
60
61impl<E: Entity> EntityId<E> {
62    /// Convert an raw [`Id`] to an [`EntityId`] for an specific [`Entity`].
63    ///
64    /// # Safety
65    /// The [`Id`] should be valid for the specified [`Entity`].
66    #[must_use]
67    pub unsafe fn from_id(value: Id) -> Self {
68        Self(value, PhantomData)
69    }
70
71    /// Return the underlying [`Id`].
72    #[must_use]
73    pub fn as_id(&self) -> Id {
74        self.0
75    }
76
77    /// Get the git reference path of this [`EntityId`].
78    #[must_use]
79    pub fn to_ref_path(&self) -> String {
80        let mut id_buf = [0; 64];
81        let id_str = self.as_id().hex_to_buf(&mut id_buf);
82
83        format!("refs/{}/{id_str}", E::NAMESPACE)
84    }
85}
86
87impl<E: Entity> Display for EntityId<E> {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        self.as_id().fmt(f)
90    }
91}