gix_object/tag/
ref_iter.rs1use bstr::BStr;
2use gix_error::{OptionExt, Result};
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) -> Result<ObjectId> {
52 let token = self.next().ok_or_raise(missing_field)??;
53 Token::into_id(token).ok_or_raise(missing_field)
54 }
55
56 pub fn tagger(mut self) -> Result<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_raise(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(mut i: &'a [u8], state: &mut State, hash_kind: gix_hash::Kind) -> Result<(&'a [u8], Token<'a>)> {
75 let input = &mut i;
76 match Self::next_inner_(input, state, hash_kind) {
77 Ok(token) => Ok((*input, token)),
78 Err(err) => Err(err),
79 }
80 }
81
82 fn next_inner_(input: &mut &'a [u8], state: &mut State, hash_kind: gix_hash::Kind) -> Result<Token<'a>> {
83 use State::*;
84 Ok(match state {
85 Target => {
86 let target = decode::target(input, hash_kind)?;
87 *state = TargetKind;
88 Token::Target {
89 id: ObjectId::from_hex(target).expect("parsing validation"),
90 }
91 }
92 TargetKind => {
93 let kind = decode::kind(input)?;
94 *state = Name;
95 Token::TargetKind(kind)
96 }
97 Name => {
98 let tag_version = decode::name(input)?;
99 *state = Tagger;
100 Token::Name(tag_version.as_bstr())
101 }
102 Tagger => {
103 *state = Message;
104 let signature = decode::tagger(input)?;
105 Token::Tagger(signature)
106 }
107 Message => {
108 let (message, signature) = decode::message(input)?;
109 debug_assert!(
110 input.is_empty(),
111 "we should have consumed all data - otherwise iter may go forever"
112 );
113 Token::Body { message, signature }
114 }
115 })
116 }
117}
118
119impl<'a> Iterator for TagRefIter<'a> {
120 type Item = Result<Token<'a>>;
121
122 fn next(&mut self) -> Option<Self::Item> {
123 if self.data.is_empty() {
124 return None;
125 }
126 match Self::next_inner(self.data, &mut self.state, self.hash_kind) {
127 Ok((data, token)) => {
128 self.data = data;
129 Some(Ok(token))
130 }
131 Err(err) => {
132 self.data = &[];
133 Some(Err(err))
134 }
135 }
136 }
137}
138
139#[expect(missing_docs)]
141#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
142pub enum Token<'a> {
143 Target {
144 id: ObjectId,
145 },
146 TargetKind(Kind),
147 Name(&'a BStr),
148 Tagger(Option<gix_actor::SignatureRef<'a>>),
149 Body {
150 message: &'a BStr,
151 signature: Option<&'a BStr>,
153 },
154}
155
156impl Token<'_> {
157 pub fn id(&self) -> Option<&oid> {
159 match self {
160 Token::Target { id } => Some(id.as_ref()),
161 _ => None,
162 }
163 }
164
165 pub fn into_id(self) -> Option<ObjectId> {
167 match self {
168 Token::Target { id } => Some(id),
169 _ => None,
170 }
171 }
172}