226 lines
6.1 KiB
Rust
226 lines
6.1 KiB
Rust
//! Shared models between server and client code.
|
|
|
|
pub use v1::HoldPosition;
|
|
pub use v1::HoldRole;
|
|
pub use v2::Hold;
|
|
pub use v2::Image;
|
|
pub use v2::ImageFilename;
|
|
pub use v2::ImageResolution;
|
|
pub use v2::ImageUid;
|
|
pub use v2::Method;
|
|
pub use v2::Problem;
|
|
pub use v2::ProblemUid;
|
|
pub use v2::Root;
|
|
pub use v2::Wall;
|
|
pub use v2::WallDimensions;
|
|
pub use v2::WallUid;
|
|
|
|
pub mod v2 {
|
|
use super::v1;
|
|
use derive_more::Display;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::collections::BTreeMap;
|
|
use std::collections::BTreeSet;
|
|
use std::fmt::Display;
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct Root {
|
|
pub walls: BTreeSet<WallUid>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct Wall {
|
|
pub uid: WallUid,
|
|
|
|
// TODO: Replace by walldimensions
|
|
pub rows: u64,
|
|
pub cols: u64,
|
|
|
|
pub holds: BTreeMap<v1::HoldPosition, Hold>,
|
|
pub problems: BTreeSet<ProblemUid>,
|
|
}
|
|
impl Wall {
|
|
pub fn random_problem(&self) -> Option<ProblemUid> {
|
|
use rand::seq::IteratorRandom;
|
|
let mut rng = rand::rng();
|
|
self.problems.iter().choose(&mut rng).copied()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
pub struct WallDimensions {
|
|
pub rows: u64,
|
|
pub cols: u64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
|
pub struct WallUid(pub uuid::Uuid);
|
|
impl WallUid {
|
|
pub fn create() -> Self {
|
|
Self(uuid::Uuid::new_v4())
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Problem {
|
|
pub uid: ProblemUid,
|
|
pub name: String,
|
|
pub set_by: String,
|
|
pub holds: BTreeMap<v1::HoldPosition, v1::HoldRole>,
|
|
pub method: Method,
|
|
pub date_added: chrono::DateTime<chrono::Utc>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
|
pub struct ProblemUid(pub uuid::Uuid);
|
|
impl ProblemUid {
|
|
pub fn create() -> Self {
|
|
Self(uuid::Uuid::new_v4())
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Display)]
|
|
pub enum Method {
|
|
#[display("Feet follow hands")]
|
|
FeetFollowHands,
|
|
|
|
#[display("Footless")]
|
|
Footless,
|
|
|
|
#[display("Footless plus kickboard")]
|
|
FootlessPlusKickboard,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Hold {
|
|
pub position: v1::HoldPosition,
|
|
pub image: Option<Image>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Image {
|
|
pub uid: ImageUid,
|
|
pub resolutions: BTreeMap<ImageResolution, ImageFilename>,
|
|
}
|
|
impl Image {
|
|
pub(crate) fn srcset(&self) -> String {
|
|
self.resolutions
|
|
.iter()
|
|
.map(|(res, filename)| format!("/files/holds/{} {}w", filename.filename, res.width))
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct ImageResolution {
|
|
pub width: u64,
|
|
pub height: u64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct ImageFilename {
|
|
pub filename: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
|
pub struct ImageUid(pub uuid::Uuid);
|
|
impl ImageUid {
|
|
pub fn create() -> Self {
|
|
Self(uuid::Uuid::new_v4())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod v1 {
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use smart_default::SmartDefault;
|
|
use std::collections::BTreeMap;
|
|
use std::collections::BTreeSet;
|
|
|
|
const STATE_VERSION: u64 = 1;
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, SmartDefault)]
|
|
pub struct PersistentState {
|
|
/// State schema version
|
|
#[default(STATE_VERSION)]
|
|
pub version: u64,
|
|
|
|
pub wall: Wall,
|
|
pub problems: Problems,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
pub struct Problems {
|
|
pub problems: BTreeSet<Problem>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Wall {
|
|
pub rows: u64,
|
|
pub cols: u64,
|
|
pub holds: BTreeMap<HoldPosition, Hold>,
|
|
}
|
|
impl Wall {
|
|
pub fn new(rows: u64, cols: u64) -> Self {
|
|
let mut holds = BTreeMap::new();
|
|
for row in 0..rows {
|
|
for col in 0..cols {
|
|
let position = HoldPosition { row, col };
|
|
let hold = Hold { position, image: None };
|
|
holds.insert(position, hold);
|
|
}
|
|
}
|
|
Self { rows, cols, holds }
|
|
}
|
|
}
|
|
impl Default for Wall {
|
|
fn default() -> Self {
|
|
Self::new(12, 12)
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
|
|
pub struct HoldPosition {
|
|
/// Starting from 0
|
|
pub row: u64,
|
|
|
|
/// Starting from 0
|
|
pub col: u64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
pub struct Problem {
|
|
pub holds: BTreeMap<HoldPosition, HoldRole>,
|
|
}
|
|
|
|
/// The role of a hold on a route
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
pub enum HoldRole {
|
|
/// Start hold
|
|
Start,
|
|
|
|
/// Any hold on the route without a specific role
|
|
Normal,
|
|
|
|
/// Zone hold
|
|
Zone,
|
|
|
|
/// End hold
|
|
End,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Hold {
|
|
pub position: HoldPosition,
|
|
pub image: Option<Image>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct Image {
|
|
pub filename: String,
|
|
}
|
|
}
|