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