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
use self::super::super::super::constraints::{SudokuBoard9x9ConciseLength, SudokuString};
use serde::de::{Deserializer, Deserialize, Error as DeserializerError};
use serde::ser::{SerializeStruct, Serializer, Serialize};
use std::str::FromStr;
use std::borrow::Cow;
#[derive_FromForm]
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct BoardMessage {
pub board_id: i32,
pub board_skeleton: String,
pub solved_board: Option<String>,
}
#[derive(Deserialize)]
struct BoardMessageData<'s> {
board_id: i32,
board_skeleton: Cow<'s, str>,
solved_board: Option<Cow<'s, str>>,
}
impl Serialize for BoardMessage {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut s = serializer.serialize_struct("BoardMessage", 2 + self.solved_board.is_some() as usize)?;
s.serialize_field("board_id", &self.board_id)?;
s.serialize_field("board_skeleton", &self.board_skeleton)?;
if let Some(ref sb) = self.solved_board {
s.serialize_field("solved_board", &sb)?;
}
s.end()
}
}
impl<'de> Deserialize<'de> for BoardMessage {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = BoardMessageData::deserialize(deserializer)?;
if data.board_id <= 0 {
Err(DeserializerError::custom("id nonpositive"))?;
}
if let Err(e) = SudokuString::<SudokuBoard9x9ConciseLength>::from_str(&data.board_skeleton) {
Err(board_error::<D>(e, "board skeleton"))?;
}
if let Some(sb) = data.solved_board.as_ref() {
if let Err(e) = SudokuString::<SudokuBoard9x9ConciseLength>::from_str(sb) {
Err(board_error::<D>(e, "solved board"))?;
}
}
Ok(BoardMessage {
board_id: data.board_id,
board_skeleton: data.board_skeleton.into(),
solved_board: data.solved_board.map(Into::into),
})
}
}
fn board_error<'de, D: Deserializer<'de>>(e: Option<Option<usize>>, name: &'static str) -> D::Error {
match e {
Some(Some(s)) => DeserializerError::custom(format_args!("{} of invalid length {}", name, s)),
Some(None) => DeserializerError::custom(format_args!("{} contained non-sudoku character", name)),
None => DeserializerError::custom(format_args!("couldn't decode {} string", name)),
}
}