Skip to content

Commit cc7b47e

Browse files
authored
feat: Core library beginnings, using it for dice rolls (#155)
* feat: Core library beginnings, using it for dice rolls * Fix clippy lints * Fix more clippy
1 parent add26e3 commit cc7b47e

18 files changed

+201
-88
lines changed

Cargo.lock

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22

33
members = [
4+
"core",
45
"ui",
56
"server"
67
]

core/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "core"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
rand = "0.8.5"

core/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Dicebag Core
2+
3+
This library contains the core functionality of Dicebag. It's intended to be used by various front-end interfaces, such as a CLI and web interface.
4+
5+
## Getting Started
6+
It's a Rust library. Import it and use it :D
7+
8+
## Testing
9+
10+
```sh
11+
cargo test
12+
```
13+
14+
## Next Steps
15+
- [] Campaign CRUD
16+
- [] Entities CRUD (Entities are information to be tracked, the base of everything--characters, items, spells, attacks, etc.)
17+
- [] Sections CRUD (Sections are collections of entities, like a character sheet or campaign notes)
18+
- [] Dice Rolls
19+
- [] Dice Roll History
20+
- [] Dice Roll Statistics
21+

core/src/campaign.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
pub struct Campaign {
2+
id: i32,
3+
name: String,
4+
description: String,
5+
}
6+
7+
impl Campaign {
8+
pub fn new(id: i32, name: String, description: String) -> Campaign {
9+
Campaign {
10+
id,
11+
name,
12+
description,
13+
}
14+
}
15+
16+
pub fn id(&self) -> i32 {
17+
self.id
18+
}
19+
20+
pub fn name(&self) -> &str {
21+
&self.name
22+
}
23+
24+
pub fn description(&self) -> &str {
25+
&self.description
26+
}
27+
28+
pub fn set_name(&mut self, name: String) {
29+
self.name = name;
30+
}
31+
32+
pub fn set_description(&mut self, description: String) {
33+
self.description = description;
34+
}
35+
}

core/src/dice.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use rand::{thread_rng, Rng};
2+
use std::num::NonZeroU8;
3+
4+
#[derive(Clone, Copy)]
5+
#[non_exhaustive]
6+
pub enum DiceType {
7+
D4,
8+
D6,
9+
D8,
10+
D10,
11+
D12,
12+
D20,
13+
D100,
14+
}
15+
16+
pub struct Roll {
17+
pub number: NonZeroU8,
18+
pub dice: DiceType,
19+
}
20+
21+
impl Roll {
22+
pub fn roll(roll: &Roll) -> Vec<i64> {
23+
let mut rng = thread_rng();
24+
(0..roll.number.into())
25+
.map(|_| rng.gen_range(1..=roll.dice.into()))
26+
.collect::<Vec<i64>>()
27+
}
28+
}
29+
30+
impl From<DiceType> for i64 {
31+
fn from(die: DiceType) -> Self {
32+
match die {
33+
DiceType::D4 => 4,
34+
DiceType::D6 => 6,
35+
DiceType::D8 => 8,
36+
DiceType::D10 => 10,
37+
DiceType::D12 => 12,
38+
DiceType::D20 => 20,
39+
DiceType::D100 => 100,
40+
}
41+
}
42+
}

core/src/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
mod campaign;
2+
mod dice;
3+
mod player;
4+
5+
pub use campaign::Campaign;
6+
pub use dice::{DiceType, Roll};
7+
pub use player::Player;
8+
9+
pub fn add(left: usize, right: usize) -> usize {
10+
left + right
11+
}
12+
13+
#[cfg(test)]
14+
mod tests {
15+
use super::*;
16+
17+
#[test]
18+
fn it_works() {
19+
let result = add(2, 2);
20+
assert_eq!(result, 4);
21+
}
22+
}

core/src/player.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
pub struct Player {
2+
id: i32,
3+
name: String,
4+
// Collection of stuff
5+
}
6+
7+
impl Player {
8+
pub fn new(id: i32, name: String) -> Player {
9+
Player {
10+
id,
11+
name,
12+
// Collection of stuff
13+
}
14+
}
15+
16+
pub fn id(&self) -> i32 {
17+
self.id
18+
}
19+
20+
pub fn name(&self) -> &str {
21+
&self.name
22+
}
23+
24+
pub fn set_name(&mut self, name: String) {
25+
self.name = name;
26+
}
27+
}

server/src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async fn get_graphql_handler(
3030
request: juniper_rocket::GraphQLRequest,
3131
schema: &State<Schema>,
3232
) -> juniper_rocket::GraphQLResponse {
33-
request.execute(&*schema, &context).await
33+
request.execute(schema, &context).await
3434
}
3535

3636
#[rocket::post("/graphql", data = "<request>")]
@@ -39,7 +39,7 @@ async fn post_graphql_handler(
3939
request: juniper_rocket::GraphQLRequest,
4040
schema: &State<Schema>,
4141
) -> juniper_rocket::GraphQLResponse {
42-
request.execute(&*schema, &context).await
42+
request.execute(schema, &context).await
4343
}
4444

4545
#[rocket::post("/")]

server/src/resolver/mod.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,18 @@ impl Mutation {
105105
use crate::schema::db::campaigns::dsl::*;
106106
use crate::schema::db::characters::dsl::{campaign_id, characters};
107107

108-
// TODO: Clean up
109-
match context
108+
let delete_result = context
110109
.run(move |c| {
111110
let characters_target = characters.filter(campaign_id.eq(delete_id));
112111
diesel::update(characters_target)
113112
.set(campaign_id.eq(None::<i32>))
114113
.execute(c)?;
115114
diesel::delete(campaigns.filter(id.eq(delete_id))).execute(c)
116115
})
117-
.await
118-
{
116+
.await;
117+
118+
// TODO: Clean up
119+
match delete_result {
119120
Ok(_) => Ok(true),
120121
Err(_) => Err(FieldError::new(
121122
"Unable to delete campaign",

ui/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ lto = true
1010

1111
[dependencies]
1212
anyhow = "1.0.58"
13+
core = { path = "../core" }
1314
getrandom = { version = "0.2.7", features = ["js"] }
1415
gloo-console = "0.2.1"
1516
graphql_client = "0.11.0"

ui/src/dice_tower/mod.rs

-42
Original file line numberDiff line numberDiff line change
@@ -1,43 +1 @@
1-
use rand::{thread_rng, Rng};
2-
use std::num::NonZeroU8;
3-
41
pub mod tower;
5-
6-
#[derive(Clone, Copy)]
7-
pub enum DiceType {
8-
D4,
9-
D6,
10-
D8,
11-
D10,
12-
D12,
13-
D20,
14-
D100,
15-
}
16-
17-
pub struct Roll {
18-
pub number: NonZeroU8,
19-
pub dice: DiceType,
20-
}
21-
22-
impl Roll {
23-
fn roll(roll: &Roll) -> Vec<i64> {
24-
let mut rng = thread_rng();
25-
(0..roll.number.into())
26-
.map(|_| rng.gen_range(1..=roll.dice.into()))
27-
.collect::<Vec<i64>>()
28-
}
29-
}
30-
31-
impl From<DiceType> for i64 {
32-
fn from(die: DiceType) -> Self {
33-
match die {
34-
DiceType::D4 => 4,
35-
DiceType::D6 => 6,
36-
DiceType::D8 => 8,
37-
DiceType::D10 => 10,
38-
DiceType::D12 => 12,
39-
DiceType::D20 => 20,
40-
DiceType::D100 => 100,
41-
}
42-
}
43-
}

ui/src/dice_tower/tower.rs

+19-32
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
use std::num::NonZeroU8;
22
use yew::{html, Component, Context, Html};
33

4-
use crate::dice_tower::Roll;
5-
6-
use super::DiceType;
7-
8-
pub enum RollMsg {
9-
D4,
10-
D6,
11-
D8,
12-
D10,
13-
D12,
14-
D20,
15-
D100,
16-
}
4+
use core::{DiceType, Roll};
175

186
pub struct Tower {
197
dice: DiceType,
208
}
219

2210
impl Component for Tower {
23-
type Message = RollMsg;
11+
type Message = DiceType;
2412
type Properties = ();
2513

2614
fn create(_ctx: &Context<Self>) -> Self {
@@ -29,16 +17,15 @@ impl Component for Tower {
2917

3018
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
3119
let (_number, dice) = match msg {
32-
RollMsg::D4 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D4),
33-
RollMsg::D6 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D6),
34-
RollMsg::D8 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D8),
35-
RollMsg::D10 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D10),
36-
RollMsg::D12 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D12),
37-
RollMsg::D20 => (NonZeroU8::new(1).unwrap(), crate::dice_tower::DiceType::D20),
38-
RollMsg::D100 => (
39-
NonZeroU8::new(1).unwrap(),
40-
crate::dice_tower::DiceType::D100,
41-
),
20+
DiceType::D4 => (NonZeroU8::new(1).unwrap(), DiceType::D4),
21+
DiceType::D6 => (NonZeroU8::new(1).unwrap(), DiceType::D6),
22+
DiceType::D8 => (NonZeroU8::new(1).unwrap(), DiceType::D8),
23+
DiceType::D10 => (NonZeroU8::new(1).unwrap(), DiceType::D10),
24+
DiceType::D12 => (NonZeroU8::new(1).unwrap(), DiceType::D12),
25+
DiceType::D20 => (NonZeroU8::new(1).unwrap(), DiceType::D20),
26+
DiceType::D100 => (NonZeroU8::new(1).unwrap(), DiceType::D100),
27+
// Other dice types are not supported
28+
_ => return false,
4229
};
4330

4431
self.dice = dice;
@@ -51,13 +38,13 @@ impl Component for Tower {
5138
}
5239

5340
fn view(&self, ctx: &Context<Self>) -> Html {
54-
let d4_click = ctx.link().callback(|_| RollMsg::D4);
55-
let d6_click = ctx.link().callback(|_| RollMsg::D6);
56-
let d8_click = ctx.link().callback(|_| RollMsg::D8);
57-
let d10_click = ctx.link().callback(|_| RollMsg::D10);
58-
let d12_click = ctx.link().callback(|_| RollMsg::D12);
59-
let d20_click = ctx.link().callback(|_| RollMsg::D20);
60-
let d100_click = ctx.link().callback(|_| RollMsg::D100);
41+
let d4_click = ctx.link().callback(|_| DiceType::D4);
42+
let d6_click = ctx.link().callback(|_| DiceType::D6);
43+
let d8_click = ctx.link().callback(|_| DiceType::D8);
44+
let d10_click = ctx.link().callback(|_| DiceType::D10);
45+
let d12_click = ctx.link().callback(|_| DiceType::D12);
46+
let d20_click = ctx.link().callback(|_| DiceType::D20);
47+
let d100_click = ctx.link().callback(|_| DiceType::D100);
6148

6249
html! {
6350
<section id="dice-tower" class="text-block">
@@ -69,7 +56,7 @@ impl Component for Tower {
6956
<button onclick={d12_click}>{ "D12" }</button>
7057
<button onclick={d20_click}>{ "D20" }</button>
7158
<button onclick={d100_click}>{ "D100" }</button>
72-
<div>{ Roll::roll(&Roll {
59+
<div>{ core::Roll::roll(&Roll {
7360
number: NonZeroU8::new(1).unwrap(),
7461
dice: self.dice,
7562
}) }</div>

ui/src/main.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ mod utils;
1616

1717
#[function_component(Dicebag)]
1818
pub fn dicebag() -> Html {
19+
#[allow(clippy::let_unit_value)]
20+
let navigation = html! { <Navigation /> };
21+
#[allow(clippy::let_unit_value)]
22+
let tower = html! { <Tower /> };
1923
html! {
2024
<BrowserRouter>
21-
<Navigation />
25+
{ navigation }
2226
<main>
2327
<Switch<AppRoute> render={Switch::render(switch)} />
2428
</main>
2529
<footer>
26-
<Tower />
30+
{ tower }
2731
<a href="https://yew.rs">
2832
<img src="/assets/yew-logo.png" alt="yew logo" />
2933
</a>

ui/src/navigation.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub fn navigation() -> Html {
6060
}
6161
}
6262

63+
#[allow(clippy::let_unit_value)]
6364
pub fn switch(routes: &AppRoute) -> Html {
6465
match routes {
6566
AppRoute::Home => html! { <HomePage /> },

0 commit comments

Comments
 (0)