state.rs 4.82 KB
Newer Older
Ryan Olson's avatar
Ryan Olson committed
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Type-state markers for the block lifecycle.
//!
//! This module defines three `pub(crate)` marker types -- [`Reset`],
//! [`Staged`], and [`Registered`] -- that are used as the `State` parameter
//! of `Block<T, State>`. Each marker carries only the data relevant to its
//! state (e.g. `Staged` holds the [`SequenceHash`](crate::SequenceHash),
//! `Registered` adds a
//! [`BlockRegistrationHandle`](crate::registry::BlockRegistrationHandle)).
//!
//! Because the state transitions are encoded as methods that consume one
//! `Block<T, S1>` and return a `Block<T, S2>`, the compiler rejects any
//! attempt to use a block in the wrong state.

use crate::KvbmSequenceHashProvider;

use super::{Block, BlockError, BlockId, BlockMetadata};
use crate::registry::BlockRegistrationHandle;

use super::{SequenceHash, TokenBlock};
use std::marker::PhantomData;

/// Marker for a block in the **Reset** state (no data assigned).
#[derive(Debug)]
pub struct Reset;

/// Marker for a block in the **Staged** state (sequence hash assigned, not
/// yet registered).
#[derive(Debug)]
pub struct Staged {
    sequence_hash: SequenceHash,
}

/// Marker for a block in the **Registered** state (present in the registry
/// with a [`BlockRegistrationHandle`]).
#[derive(Debug)]
pub struct Registered {
    sequence_hash: SequenceHash,
    registration_handle: BlockRegistrationHandle,
}

// Implementation for Reset state
impl<T> Block<T, Reset> {
    pub fn new(block_id: BlockId, block_size: usize) -> Self {
        Self {
            block_id,
            block_size,
            state: Reset,
            marker: PhantomData,
        }
    }

    /// Transition from Reset to Staged via a TokenBlock.
    /// Computes the sequence hash from the token block and stores only the hash.
    pub fn complete(
        self,
        token_block: &TokenBlock,
    ) -> Result<Block<T, Staged>, BlockError<Block<T, Reset>>> {
        if token_block.block_size() != self.block_size {
            return Err(BlockError::BlockSizeMismatch {
                expected: self.block_size,
                actual: token_block.block_size(),
                block: self, // Return the block to prevent leaks
            });
        }

        Ok(self.stage(token_block.kvbm_sequence_hash()))
    }

    /// Stage a block directly with a known sequence hash (no TokenBlock needed).
    /// Used by the mutable-block path.
    pub fn stage(self, sequence_hash: SequenceHash) -> Block<T, Staged> {
        Block {
            block_id: self.block_id,
            block_size: self.block_size,
            state: Staged { sequence_hash },
            marker: PhantomData,
        }
    }

    // pub fn reset(self) -> Block<T, Reset> {
    //     self // Already in reset state
    // }
}

// Implementation for Staged state
impl<T: BlockMetadata> Block<T, Staged> {
    pub(crate) fn register_with_handle(
        self,
        registration_handle: BlockRegistrationHandle,
    ) -> Block<T, Registered> {
        into_registered(self.block_id, self.block_size, registration_handle)
    }

    pub fn sequence_hash(&self) -> SequenceHash {
        self.state.sequence_hash
    }

    pub fn reset(self) -> Block<T, Reset> {
        Block {
            block_id: self.block_id,
            block_size: self.block_size,
            state: Reset,
            marker: PhantomData,
        }
    }
}

/// Single call site for mark_present - creates a Registered block from any prior state.
fn into_registered<T: BlockMetadata>(
    block_id: BlockId,
    block_size: usize,
    registration_handle: BlockRegistrationHandle,
) -> Block<T, Registered> {
    registration_handle.mark_present::<T>();

    Block {
        block_id,
        block_size,
        state: Registered {
            sequence_hash: registration_handle.seq_hash(),
            registration_handle,
        },
        marker: PhantomData,
    }
}

// Implementation for Registered state
impl<T: BlockMetadata> Block<T, Registered> {
    pub fn sequence_hash(&self) -> SequenceHash {
        self.state.sequence_hash
    }

    pub(crate) fn registration_handle(&self) -> &BlockRegistrationHandle {
        &self.state.registration_handle
    }

    pub fn reset(self) -> Block<T, Reset> {
        // Mark absence when destroying Block<T, Registered>
        self.state.registration_handle.mark_absent::<T>();

        // Drop the registration handle
        Block {
            block_id: self.block_id,
            block_size: self.block_size,
            state: Reset,
            marker: PhantomData,
        }
    }
}

// Common methods for all states
impl<T, State> Block<T, State> {
    #[inline]
    pub fn block_id(&self) -> BlockId {
        self.block_id
    }

    #[inline]
    pub fn block_size(&self) -> usize {
        self.block_size
    }
}