gix_object/tag/
ref_iter.rs1use bstr::BStr;
2use gix_hash::{ObjectId, oid};
3
4use crate::{Kind, TagRefIter, bstr::ByteSlice, tag::decode};
5
6#[derive(Default, Copy, Clone)]
7pub(crate) enum State {
8 #[default]
9 Target,
10 TargetKind,
11 Name,
12 Tagger,
13 Message,
14}
15
16impl<'a> TagRefIter<'a> {
17 pub fn from_bytes(data: &'a [u8], hash_kind: gix_hash::Kind) -> TagRefIter<'a> {
19 TagRefIter {
20 data,
21 state: State::default(),
22 hash_kind,
23 }
24 }
25
26 pub fn signature(data: &'a [u8]) -> Option<(crate::signature::SignatureRef<'a>, crate::signature::SignedData<'a>)> {
32 crate::signature::find(data).map(|(start, format)| {
33 (
34 crate::signature::SignatureRef {
35 format,
36 data: data[start..].as_bstr(),
37 },
38 crate::signature::SignedData::new(data, start..data.len()),
39 )
40 })
41 }
42
43 pub fn target_id(mut self) -> Result<ObjectId, crate::decode::Error> {
51 let token = self.next().ok_or_else(missing_field)??;
52 Token::into_id(token).ok_or_else(missing_field)
53 }
54
55 pub fn tagger(mut self) -> Result<Option<gix_actor::SignatureRef<'a>>, crate::decode::Error> {
58 self.find_map(|t| match t {
59 Ok(Token::Tagger(signature)) => Some(Ok(signature)),
60 Err(err) => Some(Err(err)),
61 _ => None,
62 })
63 .ok_or_else(missing_field)?
64 }
65}
66
67fn missing_field() -> crate::decode::Error {
68 crate::decode::empty_error()
69}
70
71impl<'a> TagRefIter<'a> {
72 #[inline]
73 fn next_inner(
74 mut i: &'a [u8],
75 state: &mut State,
76 hash_kind: gix_hash::Kind,
77 ) -> Result<(&'a [u8], Token<'a>), crate::decode::Error> {
78 let input = &mut i;
79 match Self::next_inner_(input, state, hash_kind) {
80 Ok(token) => Ok((*input, token)),
81 Err(err) => Err(err),
82 }
83 }
84
85 fn next_inner_(
86 input: &mut &'a [u8],
87 state: &mut State,
88 hash_kind: gix_hash::Kind,
89 ) -> Result<Token<'a>, crate::decode::Error> {
90 use State::*;
91 Ok(match state {
92 Target => {
93 let target = decode::target(input, hash_kind)?;
94 *state = TargetKind;
95 Token::Target {
96 id: ObjectId::from_hex(target).expect("parsing validation"),
97 }
98 }
99 TargetKind => {
100 let kind = decode::kind(input)?;
101 *state = Name;
102 Token::TargetKind(kind)
103 }
104 Name => {
105 let tag_version = decode::name(input)?;
106 *state = Tagger;
107 Token::Name(tag_version.as_bstr())
108 }
109 Tagger => {
110 *state = Message;
111 let signature = decode::tagger(input)?;
112 Token::Tagger(signature)
113 }
114 Message => {
115 let (message, signature) = decode::message(input)?;
116 debug_assert!(
117 input.is_empty(),
118 "we should have consumed all data - otherwise iter may go forever"
119 );
120 Token::Body { message, signature }
121 }
122 })
123 }
124}
125
126impl<'a> Iterator for TagRefIter<'a> {
127 type Item = Result<Token<'a>, crate::decode::Error>;
128
129 fn next(&mut self) -> Option<Self::Item> {
130 if self.data.is_empty() {
131 return None;
132 }
133 match Self::next_inner(self.data, &mut self.state, self.hash_kind) {
134 Ok((data, token)) => {
135 self.data = data;
136 Some(Ok(token))
137 }
138 Err(err) => {
139 self.data = &[];
140 Some(Err(err))
141 }
142 }
143 }
144}
145
146#[expect(missing_docs)]
148#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
149pub enum Token<'a> {
150 Target {
151 id: ObjectId,
152 },
153 TargetKind(Kind),
154 Name(&'a BStr),
155 Tagger(Option<gix_actor::SignatureRef<'a>>),
156 Body {
157 message: &'a BStr,
158 signature: Option<&'a BStr>,
160 },
161}
162
163impl Token<'_> {
164 pub fn id(&self) -> Option<&oid> {
166 match self {
167 Token::Target { id } => Some(id.as_ref()),
168 _ => None,
169 }
170 }
171
172 pub fn into_id(self) -> Option<ObjectId> {
174 match self {
175 Token::Target { id } => Some(id),
176 _ => None,
177 }
178 }
179}