1use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
6use mls_rs_core::group::Member;
7
8use super::{
9 confirmation_tag::ConfirmationTag, member_from_leaf_node, proposal::ReInitProposal,
10 transcript_hash::InterimTranscriptHash,
11};
12use crate::{
13 group::{GroupContext, TreeKemPublic},
14 tree_kem::node::LeafIndex,
15};
16
17#[cfg_attr(
18 all(feature = "ffi", not(test)),
19 safer_ffi_gen::ffi_type(clone, opaque)
20)]
21#[derive(Clone, Debug, PartialEq, MlsSize, MlsEncode, MlsDecode)]
22#[non_exhaustive]
23pub struct GroupState {
24 #[cfg(feature = "by_ref_proposal")]
25 pub(crate) proposals: crate::group::ProposalCache,
26 pub context: GroupContext,
27 pub(crate) public_tree: TreeKemPublic,
28 pub(crate) interim_transcript_hash: InterimTranscriptHash,
29 pub(crate) pending_reinit: Option<ReInitProposal>,
30 pub(crate) confirmation_tag: ConfirmationTag,
31}
32
33#[cfg(all(feature = "ffi", not(test)))]
34impl GroupState {
35 pub fn context(&self) -> &GroupContext {
36 &self.context
37 }
38}
39
40#[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen)]
41impl GroupState {
42 pub fn member_at_index(&self, index: u32) -> Option<Member> {
43 let Ok(leaf_index) = LeafIndex::try_from(index) else {
44 return None;
45 };
46
47 self.public_tree
48 .get_leaf_node(leaf_index)
49 .ok()
50 .map(|ln| member_from_leaf_node(ln, leaf_index))
51 }
52
53 pub(crate) fn new(
54 context: GroupContext,
55 current_tree: TreeKemPublic,
56 interim_transcript_hash: InterimTranscriptHash,
57 confirmation_tag: ConfirmationTag,
58 ) -> Self {
59 Self {
60 #[cfg(feature = "by_ref_proposal")]
61 proposals: crate::group::ProposalCache::new(
62 context.protocol_version,
63 context.group_id.clone(),
64 ),
65 context,
66 public_tree: current_tree,
67 interim_transcript_hash,
68 pending_reinit: None,
69 confirmation_tag,
70 }
71 }
72}