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
use crate::{Error, GrainId, GrainIdProto};
#[cfg(feature = "std")]
use crate::{GrainIdPrefix, GrainIdPrefixProto};
impl From<GrainId> for GrainIdProto {
fn from(value: GrainId) -> Self {
Self {
value: value.into(),
}
}
}
impl TryFrom<GrainIdProto> for GrainId {
type Error = Error;
fn try_from(value: GrainIdProto) -> Result<Self, Self::Error> {
Self::try_from(value.value)
}
}
impl GrainId {
/// "Converts a [`crate::proto::GrainId`] to [`GrainId`] by truncating bits that exceed the valid range.")]
///
/// This is a lossy conversion that masks the input value to fit within the ID's bit limit.
/// If you need to detect out-of-range values, use [`TryFrom`] instead.
///
/// # Examples
///
/// ```
/// # use grain_id::*;
/// // Values within range are preserved
/// let valid_proto = GrainIdProto { value: 123 };
/// let id = GrainId::from_proto_lossy(valid_proto);
/// assert_eq!(<GrainIdProto>::from(id), valid_proto);
///
/// // values exceeding 35 bits are truncated (MSB(s) dropped
///
/// let oversized_proto = GrainIdProto {
/// value: valid_proto.value + GrainId::CAPACITY,
/// };
/// let overflowed_id = GrainId::from_proto_lossy(oversized_proto);
/// assert_ne!(GrainIdProto::from(overflowed_id), oversized_proto);
/// // Only lower 35 bits retained
/// assert_eq!(GrainIdProto::from(overflowed_id), valid_proto);
/// ```
pub fn from_proto_lossy(value: GrainIdProto) -> Self {
Self::from_u64_lossy(value.value)
}
}
#[cfg(feature = "std")]
impl From<GrainIdPrefix> for GrainIdPrefixProto {
fn from(prefix: GrainIdPrefix) -> Self {
Self {
value: prefix.value(),
len: prefix.len() as u32,
}
}
}
#[cfg(feature = "std")]
impl TryFrom<GrainIdPrefixProto> for GrainIdPrefix {
type Error = Error;
fn try_from(proto: GrainIdPrefixProto) -> Result<Self, Self::Error> {
if proto.len > 7 {
return Err(Error::InvalidLength(proto.len as usize));
}
let len = proto.len as u8;
// Mask off any stray bits below the prefix range.
let value = if len == 0 {
0
} else {
let shift = 5 * (7 - len as u32);
(proto.value >> shift) << shift
};
Ok(GrainIdPrefix::new(value, len))
}
}
#[cfg(feature = "std")]
impl GrainIdPrefix {
/// Converts a [`GrainIdPrefixProto`] to [`GrainIdPrefix`], clamping `len` to 7
/// and masking any stray low bits in `value`.
pub fn from_proto_lossy(proto: GrainIdPrefixProto) -> Self {
let len = (proto.len as u8).min(7);
let value = if len == 0 {
0
} else {
let shift = 5 * (7 - len as u32);
(proto.value >> shift) << shift
};
Self::new(value, len)
}
}