Recursive structures - cant move reference - rust

Having an issue understanding how to handle recursive objects.
I am trying to model a price book / order book structure in rust.
Here is what I am trying to do.
struct Price {
price: u64,
side: Side,
asset_type: String,
}
struct PriceLv {
current_level: Price,
next_price_level: Option<Box<Price>>,
running_orders: LinkedList<(Qty, OrderId)>,
}
#[derive(Clone)]
pub struct OrderEntry {
pub asset: Asset,
pub price: u64,
pub side: Side,
pub user: UserId,
pub order_id: OrderId,
pub qty: u64,
}
#[derive(Clone)]
pub struct Asset {
pub name: String,
pub qty: u64,
}
impl Asset {
pub fn to_string(&self) -> String {
name.to_owned()
}
}
For sure there is more issues besides that. But when I try to add a new level I am having trouble accomplishing that.
impl PriceLv {
pub fn new(price: u64, side: Side, asset_type: Asset) -> PriceLv {
PriceLv {
current_level: Price {
price,
side,
asset_type: asset_type.to_string(),
},
next_price_level: None,
running_orders: LinkedList::new(),
}
}
pub fn add_new_order(&mut self, order_entry: &OrderEntry) {
if self.price == order_entry.price {
self.running_orders.insert((order_entry.order_id, order_entry.order_id));
}
Self::update_price_level(self, &order_entry);
}
fn update_price_level(price_level: &mut PriceLv, order_entry: &OrderEntry) -> String {
loop {
if price_level.price == order_entry.price {
price_level.current_level =
price_level.running_orders.insert((order_entry.order_id, order_entry));
return "OK".to_owned();
}
match &price_level.next_price_level {
None => {
&price_level.next_price_level = &Some(
Box::new( Price {
price: order_entry.price,
side: order_entry.side,
asset_type: order_entry.asset_type.to_string(),
})
)
}
Some(level) => {
let &tmp = Box::new( Price {
price: order_entry.price,
side: order_entry.side,
asset_type: order_entry.asset_type.to_string(),
});
*price_level.current_level = *level.as_ref();
}
}
}
}
}
How can I set current level to be the next level to continue iterate over the structure to find where to add the next level.
I suspect something to do with mem::replace / mem::swap

Related

Is there a way to fix this avoiding serde and using nanoserde instead?

I'm new to Rust and I'm using serde only to do this easy thing. I think I can use nanoserde instead but I don't know how.
I'm using serde like this:
use serde::Deserialize;
#[derive(Deserialize, Clone)]
pub struct Player {
pub team: Team,
}
#[derive(Deserialize, Clone)]
pub struct Team {
pub id: String,
// others here
}
// ...
if api_call.status().is_success() {
match serde_json::from_slice::<Player>(
&hyper::body::to_bytes(api_call.into_body()).await.unwrap(),
) {
Ok(player) => {
// use player.team here
// do something else
}
Err(err) => {
eprintln!("{err}");
}
}
}
I tried with:
match nanoserde::DeBin::de_bin::<Player>(
&hyper::body::to_bytes(api_call.into_body()).await.unwrap(),
) {
// ...
}
with no luck: it doesn't like the generics.
And tried this too:
let player: Player = nanoserde::DeBin::deserialize_bin(
&hyper::body::to_bytes(api_call.into_body()).await.unwrap(),
).unwrap();
but this doesn't work, error:
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Bin deserialize error at:8 wanted:1 bytes but max size is 1161', src\cli.rs:85:10
What does this mean?
Is there a way to fix this?
As you were lacking minimal reproducible examples, here's one for your serde code:
use serde::Deserialize;
#[derive(Deserialize, Clone)]
pub struct Player {
pub team: Team,
}
#[derive(Deserialize, Clone)]
pub struct Team {
pub id: String,
// others here
}
// ...
fn main() {
let data = br#"{"team":{"id":"42"}}"#;
match serde_json::from_slice::<Player>(data) {
Ok(player) => {
println!("Team: {}", player.team.id);
}
Err(err) => {
eprintln!("{err}");
}
};
}
Team: 42
Now let's see if we can rewrite this in nanoserde:
use nanoserde::DeJson;
#[derive(DeJson, Clone)]
pub struct Player {
pub team: Team,
}
#[derive(DeJson, Clone)]
pub struct Team {
pub id: String,
// others here
}
// ...
fn main() {
let data = r#"{"team":{"id":"42"}}"#;
match Player::deserialize_json(data) {
Ok(player) => {
println!("Team: {}", player.team.id);
}
Err(err) => {
eprintln!("{err}");
}
};
}
Team: 42
Note that we have to use a &str instead of a &[u8] here.
If we are 100% stuck with a &[u8], you can use from_utf8:
use nanoserde::DeJson;
#[derive(DeJson, Clone)]
pub struct Player {
pub team: Team,
}
#[derive(DeJson, Clone)]
pub struct Team {
pub id: String,
// others here
}
// ...
fn main() {
let data = br#"{"team":{"id":"42"}}"#;
match std::str::from_utf8(data).map(Player::deserialize_json) {
Ok(Ok(player)) => {
println!("Team: {}", player.team.id);
}
Ok(Err(err)) => {
eprintln!("{err}");
}
Err(err) => {
eprintln!("{err}");
}
};
}
Team: 42

What is the error "field `id` of struct `Todo` is private"? [duplicate]

This question already has answers here:
field of struct is private when importing module
(2 answers)
Closed 3 months ago.
I want to put a value in the structure, but I get an error because it is private. How do I resolve it?
I have it set to pub, but I get this error.
use actix_web::{get, post, web, HttpResponse,Responder};
use crate::app::model::todo::Todo;
#[get("/todos/{id}")]
async fn get_todo(id: web::Path<u32>) -> impl Responder {
let id_option: Option<u32> = Some(id.into_inner());
HttpResponse::Ok().json(Todo {
id: id_option,
content: String::from("やること"),
completed: false,
})
}
#[post("/todos")]
async fn post_todo(todo: web::Json<Todo>) -> impl Responder {
println!("post_todo");
println!("{:?}", todo);
HttpResponse::Ok().body("ok")
}
pub struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
Your struct and were is being used are not part of the same module, so declaring the struct pub won't be enough, you have to grant visibility to the fields.
This program would compile fine:
struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
fn main() {
let t = Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
but this wouldn't:
mod todo {
struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
}
fn main() {
let t = todo::Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
if you add pub to the struct but not to the fields, the struct is now visible from your main, but not its contents. If you add pub to the fields, you can create the struct from main, as well as access its fields:
mod todo {
pub struct Todo {
pub id: Option<u32>,
pub content: String,
pub completed: bool,
}
}
fn main() {
let t = todo::Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
If you make only the struct pub, but not the fields, this would allow you to see and use the structure from main, while protecting its fields from direct access:
mod todo {
pub struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
impl Todo {
pub fn new() -> Self {
Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
}
}
pub fn content(&self) -> String {
self.content.to_owned()
}
}
}
fn main() {
let t = todo::Todo::new();
println!("{}", t.content());
}
If you tried to create a struct directly from main as in Todo {.....} instead of using new(), you would get an error. if you tried to print t.content instead of using the content() function, you would get an error.

how to define multi parameter with from function in rust

Now I want to map object from Favorites to FavMusicResponse, the Favorites object was selected from database and the FavMusicResponse entity was return to the client. I define the map function like this way in FavMusicResponse:
impl From<&Favorites> for FavMusicResponse {
fn from(f: &Favorites, music: Music) -> Self {
Self{
id: f.id,
song_id: None,
created_time: f.created_time,
updated_time: f.updated_time,
user_id: 0,
source_id: "".to_string(),
like_status: 0,
source: 0,
playlist_id: 0,
play_count: 0,
fetched_download_url: None,
downloaded: None,
music: Default::default()
}
}
}
most of the fields from Favorites fields are the same with FavMusicResponse, the only difference is that music was passed from another entity. This is my FavMusicResponse define:
#[derive( Serialize, Queryable, Deserialize,Default, Clone)]
pub struct FavMusicResponse{
pub id: i64,
pub song_id: Option<i64>,
pub created_time: i64,
pub updated_time: i64,
pub user_id: i64,
pub source_id: String,
pub like_status: i32,
pub source: i32,
pub playlist_id: i64,
pub play_count: i32,
pub fetched_download_url: Option<i32>,
pub downloaded: Option<i32>,
pub music: Music
}
the compiler tell me that from expected 1 parameter, found 2, what should I do do pass 2 or more parameter into the composite function in rust? I invoke the function like this way:
let filtered_music:Vec<_> = musics.iter()
.filter(|item| item.source_id == fav.source_id)
.map(|item|FavMusicResponse::from(fav,item.clone()))
.collect();
I want to passed two entity and composite to the finally FavMusicResponse entity. what should I do to make it work like that? This is my minimal reproduce that could run in rust playground to figure out where is going wrong:
fn main() {
let music = Music{
id: 1
};
let favMusic = Favorites{
id: 1
};
let musicRes = FavMusicResponse::from(favMusic,music);
}
pub struct Music {
pub id: i64
}
pub struct Favorites {
pub id: i64
}
pub struct FavMusicResponse {
pub id: i64,
pub music:Music
}
impl From<Favorites> for FavMusicResponse {
fn from(f: Favorites, music: Music) -> Self {
Self{
id: f.id,
music: music
}
}
}
From trait can't take two parameters only one, it's define that way, the only solution if you really want to use From trait is to transform your two parameter into one, a quick solution is to use a tuple:
impl From<(Favorites, Music)> for FavMusicResponse {
fn from((f, music): (Favorites, Music)) -> Self {
Self {
id: f.id,
music,
}
}
}
// let musicRes = FavMusicResponse::from((favMusic, music));
That said you could also just have a new() method on your type:
impl FavMusicResponse {
fn new(f: Favorites, music: Music) -> Self {
Self {
id: f.id,
music,
}
}
}
// let musicRes = FavMusicResponse::new(favMusic, music);

How can i implement `std::iter::FromIterator<_>' for Struct?

When I try to make the one to many relational query for graph with diesel vie mysql, querying enum fails with fromIterator.
helps show i need to implement `std::iter::FromIterator<_> but I don't know how exactly implement the struct.
Any helps ?
thanks in advance!
error log
error[E0277]: a value of type `&std::vec::Vec<graphql::ContactContent>` cannot be built from an iterator over elements of type `_`
--> src/graphql.rs:129:89
|
129 | .and_then(|contact_contents| Ok(contact_contents.into_iter().map_into().collect()))
| ^^^^^^^ value of type `&std::vec::Vec<graphql::ContactContent>` cannot be built from `std::iter::Iterator<Item=_>`
|
= help: the trait `std::iter::FromIterator<_>` is not implemented for `&std::vec::Vec<graphql::ContactContent>`
cargo.toml
[package]
name = "lead_generation_api"
version = "0.1.0"
authors = ["ARBOR.JP"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
diesel = { version = "1.4.5", features = ["mysql", "r2d2", "chrono"] }
dotenv = "~0.15"
serde = "~1.0"
serde_derive = "~1.0"
serde_json = "~1.0"
chrono = "~0.4"
rand = "0.7.3"
actix-web = "1.0.9"
actix-cors = "0.1.0"
juniper = "0.14.1"
juniper-from-schema = "0.5.1"
juniper-eager-loading = "0.5.0"
r2d2_mysql = "*"
r2d2-diesel = "0.16.0"
mysql = "*"
r2d2 = "*"
futures01 = "0.1.29"
itertools = "0.8.2"
[[bin]]
name = "main"
path = "src/main.rs"
src/graphql.rs
use std::convert::From;
use std::sync::Arc;
use chrono::NaiveDateTime;
use actix_web::{web, Error, HttpResponse};
use futures01::future::Future;
use juniper::http::playground::playground_source;
use juniper::{http::GraphQLRequest,GraphQLObject, Executor, FieldResult, FieldError,ID};
use juniper_from_schema::graphql_schema_from_file;
use diesel::prelude::*;
use itertools::Itertools;
use crate::schema::{customers, contact_contents};
use crate::{DbCon, DbPool};
graphql_schema_from_file!("src/schema.graphql");
pub struct Context {
db_con: DbCon,
}
impl juniper::Context for Context {}
pub struct Query;
pub struct Mutation;
impl QueryFields for Query {
fn field_customers(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
) -> FieldResult<Vec<Customer>> {
//type FieldResult<T> = Result<T, String>;
customers::table
.load::<crate::models::Customer>(&executor.context().db_con)
.and_then(|customers| Ok(customers.into_iter().map_into().collect()))
.map_err(Into::into)
}
}
impl MutationFields for Mutation {
fn field_create_customer(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
name: String,
email: String,
contact_contents: Vec<String>,
) -> FieldResult<Customer> {
//type FieldResult<T> = Result<T, String>;
let new_customer = crate::models::NewCustomer { name: name, email: email};
diesel::insert_into(customers::table)
.values(&new_customer)
.execute(&executor.context().db_con);
customers::table
.first::<crate::graphql::Customer>(&executor.context().db_con)
.map_err(Into::into)
}
}
//#[derive(GraphQLObject)]
//#[graphql_object(name="customer name", email ="mail address")]
#[derive(Queryable)]
pub struct Customer {
id: u64,
name: String,
email: String,
created_at: NaiveDateTime,
updated_at: NaiveDateTime,
}
#[derive(Queryable)]
pub struct ContactContent {
id: u64,
customer_id: u64,
email: String,
}
impl ContactContentFields for ContactContent {
fn field_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.id.to_string()))
}
fn field_customer_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.customer_id.to_string()))
}
fn field_email(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.email)
}
}
impl From<crate::models::ContactContent> for ContactContent {
fn from(contact_contents: crate::models::ContactContent) -> Self {
Self {
id: contact_contents.id,
customer_id: contact_contents.customer_id,
email: contact_contents.email,
}
}
}
//#[juniper::object(Context = Context)]
//#[graphql(description = "A Photo returns struct")]
impl CustomerFields for Customer {
fn field_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.id.to_string()))
}
fn field_name(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.name)
}
fn field_email(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.email)
}
fn field_contact_contents(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, ContactContent, Walked>,
) -> FieldResult<&Vec<ContactContent>> {
contact_contents::table
.filter(contact_contents::customer_id.eq(&self.id))
.load::<crate::models::ContactContent>(&executor.context().db_con)
.and_then(|contact_contents| Ok(contact_contents.into_iter().map_into().collect()))
.map_err(Into::into)
}
}
impl From<crate::models::Customer> for Customer {
fn from(customer: crate::models::Customer) -> Self {
Self {
id: customer.id,
name: customer.name,
email: customer.email,
created_at: customer.created_at,
updated_at: customer.updated_at,
}
}
}
fn playground() -> HttpResponse {
let html = playground_source("");
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html)
}
fn graphql(
schema: web::Data<Arc<Schema>>,
data: web::Json<GraphQLRequest>,
db_pool: web::Data<DbPool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
let ctx = Context {
db_con: db_pool.get().unwrap(),
};
web::block(move || {
let res = data.execute(&schema, &ctx);
Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?)
})
.map_err(Error::from)
.and_then(|customer| {
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(customer))
})
}
pub fn register(config: &mut web::ServiceConfig) {
let schema = std::sync::Arc::new(Schema::new(Query, Mutation));
config
.data(schema)
.route("/", web::post().to_async(graphql))
.route("/", web::get().to(playground));
}
src/schema.rs
table! {
contact_contents (id) {
id -> Unsigned<Bigint>,
customer_id -> Unsigned<Bigint>,
email -> Varchar,
}
}
table! {
customers (id) {
id -> Unsigned<Bigint>,
name -> Varchar,
email -> Varchar,
created_at -> Timestamp,
updated_at -> Timestamp,
}
}
src/schema.graphql
schema {
query: Query
mutation: Mutation
}
type Query {
customers: [Customer!]! #juniper(ownership: "owned")
}
type Mutation {
createCustomer(
name: String!
email: String!
contactContents: [String!]!
): Customer! #juniper(ownership: "owned")
}
type Customer {
id: ID! #juniper(ownership: "owned")
name: String!
email: String!
contactContents: [ContactContent!]!
}
type ContactContent {
id: ID! #juniper(ownership: "owned")
customerId: ID! #juniper(ownership: "owned")
email: String!
}
src/models.rs
use chrono::NaiveDateTime;
pub struct Query;
pub struct Mutation;
#[derive(Queryable, Identifiable, AsChangeset, Clone, PartialEq, Debug)]
pub struct Customer {
pub id: u64,
pub name: String,
pub email: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
}
use super::schema::customers;
#[derive(Queryable,Insertable, AsChangeset)]
#[table_name="customers"]
pub struct NewCustomer {
pub name: String,
pub email: String,
}
use super::schema::contact_contents;
#[derive(Queryable,Identifiable)]
#[table_name="contact_contents"]
pub struct ContactContent {
pub id: u64,
pub customer_id: u64,
pub email: String,
}
src/main.rs
#[macro_use]
extern crate diesel;
extern crate r2d2;
use actix_cors::Cors;
use actix_web::{web, App, HttpServer};
use diesel::{
prelude::*,
};
use diesel::r2d2::ConnectionManager;
pub mod graphql;
pub mod models;
pub mod schema;
pub type DbPool = r2d2::Pool<ConnectionManager<MysqlConnection>>;
pub type DbCon = r2d2::PooledConnection<ConnectionManager<MysqlConnection>>;
fn main() {
let db_pool = create_db_pool();
let port: u16 = std::env::var("PORT")
.ok()
.and_then(|p| p.parse().ok())
.unwrap_or(8080);
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));
HttpServer::new(move || {
App::new()
.data(db_pool.clone())
.wrap(Cors::new())
.configure(graphql::register)
.default_service(web::to(|| "404"))
})
.bind(addr)
.unwrap()
.run()
.unwrap();
}
pub fn create_db_pool() -> DbPool {
let manager = ConnectionManager::<MysqlConnection>::new("mysql://root:example#mysql/test");
r2d2::Pool::new(manager).expect("Failed to create DB Pool")
}
There's nothing to implement, the issue here is that the typing of field_contact_contents is not correct: &Vec<ContactContent> would mean that it returns a member of one of its parameters somehow.
Since you're not borrowing the vec from somewhere but creating it from whole cloth inside the method, that makes no sense, the method should return a proper Vec.
Here's a trivial reproduction case: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8f0b6341f7ffd72fe8de334a098295a1

Why does variable need to continue living after output is consumed?

use std::cell::RefCell;
use std::collections::VecDeque;
// minimum reproducible example for stack overflow question
// which is essentially the whole thing b/c all of these types
// depend on each other
// this is an implementation of Monopoly Deal (see http://monopolydealrules.com/)
// but the only relevant part to the question is in main(), around line 400
// card.rs
pub trait Card {
fn value(&self) -> i32;
fn kind(&self) -> CardKind;
}
pub enum CardKind {
Money,
Action,
Property,
Building,
}
// property.rs
pub struct PropertySet {
color: Color,
properties: Vec<Property>,
house: bool,
hotel: bool,
}
impl PropertySet {
pub fn rent(&self) -> i32 {
unimplemented!() // stub
}
pub fn color(&self) -> Color {
self.color
}
pub fn properties(&self) -> &Vec<Property> {
&self.properties
}
pub fn is_full(&self) -> bool {
self.properties().len() == self.color.set_size() as usize
}
pub fn is_empty(&self) -> bool {
self.properties().len() == 0
}
pub fn add(&mut self, property: Property) -> Result<(), PropertySetAddError> {
if !property.matches(self.color) {
return Err(PropertySetAddError {
property,
kind: PropertySetAddErrorKind::WrongColor,
});
}
if self.properties.len() + 1 < self.color.set_size() as usize {
self.properties.push(property);
Ok(())
} else {
Err(PropertySetAddError {
property,
kind: PropertySetAddErrorKind::SetFull,
})
}
}
fn remove(&mut self, index: usize) -> Property {
self.properties.remove(index)
}
}
pub struct PropertySetAddError {
property: Property,
kind: PropertySetAddErrorKind,
}
pub enum PropertySetAddErrorKind {
WrongColor,
SetFull,
}
pub enum Property {
Basic { name: String, color: Color },
Wild { colors: [Color; 2], value: i32 },
Any,
}
impl Card for Property {
fn value(&self) -> i32 {
unimplemented!() // stub
}
fn kind(&self) -> CardKind {
CardKind::Property
}
}
impl Property {
pub fn matches(&self, color: Color) -> bool {
unimplemented!() // stub
}
}
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
pub enum Color {
Red,
Orange,
Yellow,
Green,
LightBlue,
DarkBlue,
Magenta,
Brown,
Utility,
Railroad,
}
impl Color {
pub fn set_size(&self) -> i32 {
unimplemented!() // stub
}
}
// money.rs
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Money(pub i32);
impl Card for Money {
fn value(&self) -> i32 {
self.0
}
fn kind(&self) -> CardKind {
CardKind::Money
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Id(pub usize);
pub struct Possessions {
bank: Vec<Money>,
hand: Vec<Box<dyn Card>>,
properties: Vec<PropertySet>,
}
// brain.rs
pub trait Brain {
fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect>;
fn react(
&self,
state: &GameState,
possessions: &mut Possessions,
effect: &Effect,
) -> Vec<Effect>;
}
pub struct Human {}
impl Human {
pub fn new() -> Human {
Human {}
}
}
impl Brain for Human {
fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect> {
unimplemented!()
}
fn react(
&self,
state: &GameState,
possessions: &mut Possessions,
effect: &Effect,
) -> Vec<Effect> {
unimplemented!()
}
}
// action.rs
pub enum Action {
Rent { colors: [Color; 2] },
AnyRent,
DoubleRent,
DealBreaker,
DebtCollector,
Birthday,
SayNo,
PassGo,
SlyDeal,
ForcedDeal,
}
impl Card for Action {
fn value(&self) -> i32 {
unimplemented!() // stub
}
fn kind(&self) -> CardKind {
CardKind::Action
}
}
impl Action {
pub fn effect<'a>(
&self,
source: Id,
target: ActionTarget<'a>,
) -> Result<Effect<'a>, EffectError> {
unimplemented!() // stub
}
}
pub enum ActionTarget<'a> {
None,
Player {
player: Id,
},
Set {
/// The player that this action is targeted against
player: Id,
/// Can be a set that player owns, such as in the case of Deal Breaker, or it
/// can be a set that the source owns, such as in the case of rent cards
set: &'a PropertySet,
},
Property {
player: Id,
property: (&'a PropertySet, usize),
},
Swap {
player: Id,
take: (&'a PropertySet, usize),
give: (&'a PropertySet, usize),
},
}
// effect.rs
#[derive(Clone)]
pub enum Effect<'a> {
// swaps properties with another player
Swap {
source: Id,
target: Id,
give: (&'a PropertySet, usize),
take: (&'a PropertySet, usize),
},
// steals properties from another player
Steal {
source: Id,
target: Id,
set: &'a PropertySet,
indices: Vec<usize>,
},
// charges another player
Charge {
source: Id,
target: Option<Id>,
amount: i32,
reason: ChargeReason,
},
// cancels prior effect
Cancel {
source: Id,
target: Id,
},
// pass Go, credit $2M
Go {
source: Id,
},
}
#[derive(Clone)]
pub enum ChargeReason {
Rent,
Birthday,
DebtCollector,
}
pub enum EffectError {
/// The target supplied was not valid for this action.
InvalidTarget,
/// You tried to charge rent for a color, but the specified set isn't that color
NoProperty,
}
// player.rs
pub struct Player {
pub id: Id,
pub name: String,
pub possessions: Possessions,
pub brain: Box<dyn Brain>,
}
impl Player {
pub fn new(id: Id, name: String, brain: Box<dyn Brain>) -> Player {
Player {
id,
possessions: Possessions {
bank: vec![],
hand: vec![],
properties: vec![],
},
name,
brain,
}
}
pub fn id(&self) -> Id {
self.id
}
pub fn bank(&self) -> &Vec<Money> {
&self.possessions.bank
}
pub fn properties(&self) -> &Vec<PropertySet> {
&self.possessions.properties
}
pub fn name(&self) -> &str {
&self.name
}
pub fn brain(&self) -> &Box<dyn Brain> {
&self.brain
}
pub fn act(&mut self, state: &GameState) -> Vec<Effect> {
self.brain.act(state, &mut self.possessions)
}
pub fn react(&mut self, state: &GameState, effect: &Effect) -> Vec<Effect> {
self.brain.react(state, &mut self.possessions, effect)
}
}
// state.rs
pub struct GameState {
pub players: Vec<RefCell<Player>>,
pub current: Id,
pub stack: Vec<Box<dyn Card>>,
}
impl GameState {
pub fn next(&mut self) {
self.current = Id((self.current.0 + 1) % self.players.len())
}
pub fn current_player(&self) -> &RefCell<Player> {
self.players.get(self.current.0).unwrap()
}
pub fn get_player(&self, id: Id) -> Option<&RefCell<Player>> {
self.players.get(id.0)
}
}
// deck.rs
pub fn create_deck() -> Vec<Box<dyn Card>> {
vec![
// ...
]
}
// main.rs
pub fn main() {
let brain = Human::new(); // Human implements Brain
let me = Player::new(Id(0), "Ibi".to_owned(), Box::new(brain));
let current = me.id();
let players = vec![RefCell::new(me)];
let stack = create_deck(); // returns Vec<Box<dyn Card>>
let mut state = GameState {
players,
stack,
current,
};
while !state.players.iter().any(|player| {
player
.borrow()
.properties()
.iter()
.filter(|&set| set.is_full())
.count()
>= 3
}) {
// ...
let mut effects = VecDeque::new();
{
let mut current_player = state.current_player().borrow_mut();
let action = current_player.act(&state);
effects.extend(action);
}
// let all other players react to effects until no more reactions are generated
while !effects.is_empty() {
let effect = effects.pop_front().unwrap();
// ...
}
}
}
I can't get this code to compile; it says that current_player does not live long enough and complains that it is dropped at the end of the block. Why does current_player need to survive beyond the end of the block? My understanding is that it returns a Vec<Effect> which my method now owns, and then that vector is consumed by extend() and the values it contained are now owned by effects, so why is current_player still necessary?

Resources