-
Notifications
You must be signed in to change notification settings - Fork 144
Expand file tree
/
Copy pathblock.rs
More file actions
163 lines (141 loc) · 3.97 KB
/
block.rs
File metadata and controls
163 lines (141 loc) · 3.97 KB
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
use bytemuck::{Pod, Zeroable};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use libcraft_core::{BlockPosition, ChunkPosition, Position};
use std::convert::TryFrom;
/// Validated position of a block.
///
/// This structure is immutable.
/// All operations that change a [`ValidBlockPosition`] must be done by
/// turning it into a [`BlockPosition`], performing said operations,
/// then using [`ValidBlockPosition`]'s [`TryFrom`] impl to get a [`ValidBlockPosition`].
///
/// The definition of a valid block position is defined by [`BlockPosition::valid`].
///
/// # Examples
///
/// Converting a [`BlockPosition`] to a [`ValidBlockPosition`], unwrapping any errors that
/// occur.
/// ```
/// # use feather_base::BlockPosition;
/// # use feather_base::ValidBlockPosition;
/// # use std::convert::TryInto;
/// // Create an unvalidated block position
/// let block_position = BlockPosition::new(727, 32, 727);
///
/// // Validate the block position and unwrap any errors
/// let valid_block_position: ValidBlockPosition = block_position.try_into().unwrap();
/// ```
///
/// Performing operations on a [`ValidBlockPosition`], then re-validating it.
/// ```
/// # use feather_base::BlockPosition;
/// # use feather_base::ValidBlockPosition;
/// # use std::convert::TryInto;
/// # let mut valid_block_position: ValidBlockPosition = BlockPosition::new(727, 32, 727).try_into().unwrap();
/// // Convert the ValidBlockPosition into an unvalidated one to perform math
/// let mut block_position: BlockPosition = valid_block_position.into();
///
/// block_position.x = 821;
/// block_position.z += 32;
///
/// assert!(block_position.valid());
///
/// valid_block_position = block_position.try_into().unwrap();
/// ```
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
Zeroable,
Pod,
)]
#[repr(C)]
pub struct ValidBlockPosition {
x: i32,
y: i32,
z: i32,
}
impl ValidBlockPosition {
pub fn x(&self) -> i32 {
self.x
}
pub fn y(&self) -> i32 {
self.y
}
pub fn z(&self) -> i32 {
self.z
}
pub fn chunk(self) -> ChunkPosition {
self.into()
}
pub fn position(self) -> Position {
self.into()
}
}
impl TryFrom<BlockPosition> for ValidBlockPosition {
type Error = BlockPositionValidationError;
fn try_from(value: BlockPosition) -> Result<Self, Self::Error> {
if value.valid() {
Ok(ValidBlockPosition {
x: value.x,
y: value.y,
z: value.z,
})
} else {
Err(BlockPositionValidationError::OutOfRange(value))
}
}
}
impl From<ValidBlockPosition> for BlockPosition {
fn from(position: ValidBlockPosition) -> Self {
BlockPosition {
x: position.x,
y: position.y,
z: position.z,
}
}
}
impl From<ValidBlockPosition> for ChunkPosition {
fn from(position: ValidBlockPosition) -> Self {
let position: BlockPosition = position.into();
position.into()
}
}
impl From<ValidBlockPosition> for Position {
fn from(position: ValidBlockPosition) -> Self {
let position: BlockPosition = position.into();
position.into()
}
}
#[derive(Error, Debug)]
pub enum BlockPositionValidationError {
#[error("coordinate {0:?} out of range")]
OutOfRange(BlockPosition),
}
#[cfg(test)]
mod tests {
use std::convert::TryInto;
use libcraft_core::BlockPosition;
use crate::ValidBlockPosition;
#[test]
#[should_panic]
fn check_out_of_bounds_up() {
let block_position = BlockPosition::new(0, 39483298, 0);
<BlockPosition as TryInto<ValidBlockPosition>>::try_into(block_position).unwrap();
}
#[test]
#[should_panic]
fn check_out_of_bounds_down() {
let block_position = BlockPosition::new(0, -39483298, 0);
<BlockPosition as TryInto<ValidBlockPosition>>::try_into(block_position).unwrap();
}
}