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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#![warn(missing_docs)]

//! This crate contains shared data for the other MCVM crates
//!
//! # Features:
//!
//! - `schema`: Enable generation of JSON schemas using the `schemars` crate

/// Common addon constructs
pub mod addon;
/// Tools for languages and language detection
pub mod lang;
/// Enums for modifications to the game
pub mod modifications;
/// MCVM output
pub mod output;
/// Common package constructs
pub mod pkg;
/// Other utilities
pub mod util;
/// Tools for dealing with version patterns
pub mod versions;

use std::{fmt::Display, str::FromStr};

use anyhow::anyhow;
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

/// The Later<T> enum
pub mod later {
	/// An enum very similar to `Option<T>` that lets us access it with an easier assertion.
	/// It is meant for data that we know should already be full at some point.
	#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
	pub enum Later<T> {
		/// The Later does not contain a value
		#[default]
		Empty,
		/// The later does contain a value
		Full(T),
	}

	impl<T> Later<T> {
		/// Construct an empty Later
		#[inline(always)]
		pub fn new() -> Self {
			Self::Empty
		}

		/// Fill the Later with a value
		#[inline(always)]
		pub fn fill(&mut self, value: T) {
			*self = Self::Full(value);
		}

		/// Fill the Later with a function if it is not full already
		pub fn ensure_full(&mut self, f: impl Fn() -> T) {
			if self.is_empty() {
				self.fill(f());
			}
		}

		/// Clear the Later
		#[inline(always)]
		pub fn clear(&mut self) {
			*self = Self::Empty;
		}

		/// Checks if the Later does not contain a value
		#[must_use]
		#[inline(always)]
		pub fn is_empty(&self) -> bool {
			matches!(self, Self::Empty)
		}

		/// Checks if the Later does contain a value
		#[must_use]
		#[inline(always)]
		pub fn is_full(&self) -> bool {
			matches!(self, Self::Full(..))
		}

		/// Grab the value inside and panic if it isn't there
		#[inline(always)]
		pub fn get(&self) -> &T {
			if let Self::Full(value) = self {
				value
			} else {
				self.fail();
			}
		}

		/// Grab the value inside mutably and panic if it isn't there
		#[inline(always)]
		pub fn get_mut(&mut self) -> &mut T {
			if let Self::Full(value) = self {
				value
			} else {
				self.fail();
			}
		}

		/// Grab the value inside without a reference and panic if it isn't there
		#[inline(always)]
		pub fn get_val(self) -> T {
			if let Self::Full(value) = self {
				value
			} else {
				self.fail();
			}
		}

		/// Converts to an `Option<T>`
		#[inline(always)]
		pub fn into_option(self) -> Option<T> {
			match self {
				Self::Empty => None,
				Self::Full(val) => Some(val),
			}
		}

		fn fail(&self) -> ! {
			panic!("Value in Later<T> does not exist");
		}
	}

	impl<T: Clone> Later<T> {
		/// Grab the value by cloning and panic if it isn't there
		pub fn get_clone(&self) -> T {
			if let Self::Full(value) = self {
				value.clone()
			} else {
				self.fail();
			}
		}
	}

	#[cfg(test)]
	mod tests {
		use super::*;

		#[test]
		fn test_later_fill() {
			let mut later = Later::new();
			later.fill(7);
			later.get();
		}

		#[test]
		#[should_panic(expected = "Value in Later<T> does not exist")]
		fn test_later_fail() {
			let later: Later<i32> = Later::new();
			later.get();
		}
	}
}

/// Minecraft game side, client or server
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum Side {
	/// The default game
	Client,
	/// A dedicated server
	Server,
}

impl Side {
	/// Parse a Side from a string
	pub fn parse_from_str(string: &str) -> Option<Self> {
		match string {
			"client" => Some(Self::Client),
			"server" => Some(Self::Server),
			_ => None,
		}
	}
}

impl FromStr for Side {
	type Err = anyhow::Error;

	fn from_str(s: &str) -> Result<Self, Self::Err> {
		Self::parse_from_str(s).ok_or(anyhow!("Not a valid side"))
	}
}

impl Display for Side {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(
			f,
			"{}",
			match self {
				Self::Client => "client",
				Self::Server => "server",
			}
		)
	}
}