How can one set a variable number of input accounts for a an instruction wrapper?
i.e. given this:
#[derive(Accounts)]
pub struct Initialize<'info> {
...I'd like to specify here a random number of accounts
}
This is useful when you would want to refer to all creators of a digital asset (say NFT), but you don't know in advance how many there are.
Oh, I have just found out you can use something like this:
pub fn do_something(ctx: Context<Initialize>) -> ProgramResult {
let vec: Vec<AccountInfo> = ctx.remaining_accounts.into_vec();
// do something with the accounts
Ok(())
}
Related
For my first project I wanted to create a terminal implementation of Monopoly. I have created a Card, Player, and App structs. Originally my plan was to create an array inside the App struct holding a list of cards which I could then randomly select and run an execute() method on, which would push a log to the logs field of the App. What I thought would be best was this:
pub struct Card {
pub group: u8,
pub name: String,
pub id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Card {
Card { group, name, id }
}
pub fn execute(self, app: &mut App) {
match self.id {
1 => {
app.players[app.current_player].index = 24;
app.push_log("this works".to_string(), "LOG: ".to_string());
}
_ => {}
}
}
}
pub struct Player<'a> {
pub name: &'a str,
pub money: u64,
pub index: u8,
pub piece: char,
pub properties: Vec<u8>,
pub goojf: u8, // get out of jail freeh
}
impl<'a> Player<'a> {
pub fn new(name: &'a str, piece: char) -> Player<'a> {
Player {
name,
money: 1500,
index: 0,
piece,
properties: Vec::new(),
goojf: 0,
}
}
}
pub struct App<'a> {
pub cards: [Card; 1],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new() -> App<'a> {
App {
cards: [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)],
logs: vec![(
String::from("You've begun a game!"),
String::from("BEGIN!:"),
)],
players: vec![Player::new("Joe", '#')],
current_player: 0,
}
}
pub fn draw_card(&mut self) {
if self.players[self.current_player].index == 2
|| self.players[self.current_player].index == 17
|| self.players[self.current_player].index == 33
{
self.cards[0].execute(self);
}
}
pub fn push_log(&mut self, message: String, status: String) {
self.logs.push((message, status));
}
}
fn main() {}
However this code throws the following error:
error[E0507]: cannot move out of `self.cards[_]` which is behind a mutable reference
--> src/main.rs:76:13
|
76 | self.cards[0].execute(self);
| ^^^^^^^^^^^^^ move occurs because `self.cards[_]` has type `Card`, which does not implement the `Copy` trait
I managed to fix this error by simply declaring the array of cards in the method itself, however, this seem to be pretty brute and not at all efficient, especially since other methods in my program depend on cards. How could I just refer to a single array of cards for all of my methods implemented in App or elsewhere?
As others have pointed out, Card::execute() needs to take &self instead of self, but then you run into the borrow checker issue, which I'll spend the rest of this answer discussing.
It may seem odd, but Rust is actually protecting you here. The borrow checker does not look into functions to see what they do, so it has no idea that Card::execute() won't do something to invalidate the referenced passed as the first argument. For example, if App::cards was a vector instead of an array, it could clear the vector.
Something that could actually practically happen here to cause undefined behavior would be if Card::execute() took a string slice from self.name and then cleared the card's name attribute through the mutable reference to app. None of these actions would be prohibited, and you'd be left with an invalid reference to a string slice. This is why the borrow checker isn't letting you make this method call, and this is exactly the kind of accident that Rust is designed to prevent.
There's a few ways around this. One option is to only pass the pieces of the App value needed to complete the task. You can borrow different parts of the same value. The problem here is that the reborrow of self overlaps with the borrow self.cards[0]. Passing each field separately isn't very ergonomic though, as in this case you'll wind up having to pass a reference to pretty much everything else on App.
It looks like the Card values don't actually contain any game state, and are used as data for the game engine. If this is the case, then the cards can live outside of App, like so:
pub struct App<'a> {
// Changed to an unowned slice.
pub cards: &'a [Card],
pub logs: Vec<(String, String)>,
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
impl<'a> App<'a> {
pub fn new(cards: &'a [Card]) -> App<'a> {
App {
cards,
// ...
Then in your main() you can initialize the data and borrow it:
fn main() {
let cards: [Card; 1] = [Card::new(
11,
"Take a ride on the Penn. Railroad!".to_string(),
0,
)];
let app = App::new(&cards);
}
This solves the compilation problem. I'd suggest making other changes, as well:
App should probably be renamed GameState or something to emphasize that this struct should contain only mutable game state, and no immutable reference data.
Player's name field should probably be an owned String instead of an unowned &str, otherwise some other entity in the program will need to own a string slice for the duration of the program so that Player can borrow it.
Does a card need to be able to mutate the cards in self? If you know that execute will not need access to cards, the easiest solution is to split App into further structs so you can better limit the access of the function.
Unless there is another layer to your program that interacts with App as a singular object, requiring everything be in a single struct to perform operations will likely only constrain your code. If possible it is better to split it into its core components so you can be more selective when sharing references and avoid needing to make so many fields pub.
Here is a rough example:
pub struct GameState<'a> {
pub players: Vec<Player<'a>>,
pub current_player: usize,
}
/// You may want to look into using https://crates.io/crates/log instead to make logging easier.
pub struct Logs {
entries: Vec<(String, String)>,
}
impl Logs {
/// Use ToOwned so you can use both both &str and String
pub fn push<S: ToOwned<String>>(&mut self, message: S, status: S) {
self.entries.push((message.to_owned(), status.to_owned()));
}
}
pub struct Card {
group: u8,
name: String,
id: u8,
}
impl Card {
pub fn new(group: u8, name: String, id: u8) -> Self {
Card { group, name, id }
}
/// Use &self because there is no reason we need are required to consume the card
pub fn execute(&self, state: &mut GameState, logs: &mut Logs) {
if self.id == 1{
state.players[state.current_player].index = 24;
logs.push("this works", "LOG");
}
}
}
Also as a side note, execute consumes a card when called since it does not take a reference. Since Card does not implement Copy, that would require it be removed from cards so it can be moved.
Misc Tips and Code Review
Using IDs
It looks like you frequently use IDs to distinguish between items. However, I think your code will look cleaner and be easier to write if you used more human readable types. For example, do cards need an ID? Usually it is preferable to define your struct based on how the data is used. Last time I played monopoly, I don't remember picking up a card and referring to the card ID to determine what to do. I would instead recommend defining a Card by how it is used in the came. If I am remembering correctly, each card contains a short message telling the player what to do. Technically a card could consist of just the message, but you can instead make your code a bit cleaner by separating out the action to an enum so actions are not hard coded to the text on the card.
pub struct Card {
text: String,
action: CardAction,
}
// Note: enums which can also hold data, are more commonly referred to as
// "tagged unions" in computer science. It can be a pain to search for them if
// you don't know what they are called.
pub enum CardAction {
ProceedToGo,
GoToJail,
GainOrLoseMoney(i64),
// etc.
}
On a similar note, it looks like you are trying to be memory conscious by using the smallest type required for a given value. I would recommend against this thinking. If a value of 253u8 is equally as invalid as 324234i32, then the smaller type is not doing anything to help you. You might as well use i32/u32 or i64/u64 since most systems will have an easier time operating on these types. The same thing goes for indices and using other integer types instead of usize since choosing to use another type will only give you more work converting it to and from a usize.
Sharing Owned References
Depending on your design philosophy you might want to store a reference to a struct in multiple places. This can be done using a reference counter Rc<T>. Here are some quick examples. Note that these can not be shared between threads.
let property: Rc<Property> = Rc::new(Property::new(/* etc */));
// Holds an owned reference to the same property as property that can be accessed immutably
let ref_to_property: Rc<Property> = property.clone();
// Or if you want interior mutability you can use Rc<RefCell<T>> instead.
let mutable_property = Rc::new(RefCell::new(Property::new(/* etc */)));
To make the question more clear, i am trying to find a better way for the below task, say i have a Config struct which will be initialised with the config values provided by user, but all the configs are optional, in the case that user didn't provide a value, then it will be initialised with some default values.
pub struct Config {
pub a: Option<u128>,
pub b: Option<Duration>
// ...
}
impl Config {
pub fn new() -> Self {
// ...
Self {
// ...
}
}
}
My confusion is that even i know for sure that each field of the Config instance i get from the Config::new() function has a solid value Some(x), but still in the later program everywhere when i need a value from this config instance, i need to call unwrap, is there a better way to avoid these ubiquitous unwrap?
Or is there a better design i should go with?
I am still learning rust, sorry if it is some stupid questions.
In general: One way to go is to have two structs. One with all things Options, and another with all of them plain values, and a function to create an Option of the latter from the former.
struct ConfigPre {
pub a: Option<u128>,
pub b: Option<Duration>,
}
struct Config {
pub a: u128,
pub b: Duration,
}
impl Config {
fn new(from: ConfigPre) -> Option<Self> {
Some(Self { a: from.a?, b: from.b? })
}
}
This is tedious to type out, and you can take it one step further by using builders and have this code + some convenience setters autogenerated. Try e.g. typed-builder.
In your specific case: If you set all the values of Config to Some in new, why do they need to be Options in the first place?
I have a struct containing general config data for a web application:
#[derive(Debug)]
pub struct AppConfig {
pub db_host: String,
pub timeout: Duration,
pub jwt_signing_key: String,
// more fields
}
jwt_signing_key is a symmetric jwt secret, so much be kept confidential/
This works fine, but I would like to be able to log the contents of an AppConfig for debugging purposes without the JWT secret appearing in logs. Ideally, it would return something along the lines of:
AppConfig {
db_host: "https://blah"
jwt_signing_key: "**********" // key obfuscated
}
One option is to create a thin wrapper:
pub struct AppConfig {
// ...
pub jwt_signing_key: JwtSigningKey,
}
pub struct JwtSigningKey(String);
// custom implementation of Debug
But this would require a large-ish refactor and adds an unnecessary (in my opinion) layer of indirection. (I'm not worried about the performance, but more the code noise)
AppConfig is relatively large and maintaining a manual Debug implementation is extra work I'd rather not have to do every time I want to add a field.
Is there an easier solution?
One option is to create a thin wrapper:
pub struct AppConfig {
// ...
pub jwt_signing_key: JwtSigningKey,
}
pub struct JwtSigningKey(String);
// custom implementation of Debug
I think you should go with this option. The advantage it has is that no matter where in your application the value ends up, it will never be accidentally printed — or used in any other way — without explicitly unwrapping it, whereas replacing Debug of the AppConfig struct will only assist with that one particular case. It's robust against mistakes made while refactoring, too.
The type doesn't have to be so specific as JwtSigningKey; it could be just pub struct Secret<T>(T); and support any kind of secrets you end up working with. There are even libraries to provide such a type (see this thread for comments comparing two of them) which add more features like zeroing the memory when dropped (so that it's less likely that any accidental leak of memory contents might reveal a secret).
See this thread. Essentially, the best way to do it right now is to use the derivative crate, which allows you to do something like this:
use derivative::Derivative;
use std::fmt;
fn obfuscated_formatter(val: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", "*".repeat(val.len()))
}
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
normal: String,
#[derivative(Debug(format_with = "obfuscated_formatter"))]
secret: String
}
fn main() {
let foo = Foo {
normal: "asdf".into(),
secret: "foobar".into()
};
println!("{:?}", foo);
}
Playground link
I'm writing a library in Rust using the gpio_cdev crate.
I have a struct, and one of its functions looks like this:
pub fn add_channel(&mut self, name: String, pin: u8) -> Result<(), gpio_cdev::Error> {
let line = self.chip.get_line(pin as u32)?;
...
}
This works fine. Now I want to add validation to the input pin, so that it's not out-of-range. I know this isn't strictly necessary, and that an invalid pin will get caught by chip.get_line(), but this gives a friendlier error message, and can even allow me to place artificial limits on usable pins (ex: if pins above 20 can technically be used, but I know they should never be used by this function).
My code now looks like this:
pub fn add_channel(&mut self, name: String, pin: u8) -> Result<(), gpio_cdev::Error> {
if pin > 20 {
return Err(gpio_cdev::Error::new(format!("Pin {} is out of range!", pin)));
}
let line = self.chip.get_line(pin as u32)?;
...
}
I would think something like that would work, but gpio_cdev::Error doesn't have a new method, or any other way I can figure out to create an instance of it. Is there a way to do this? Or am I doing something fundamentally wrong? Is this struct only meant to be used internally, within the gpio_cdev crate, without any way to create instances from outside the crate?
gpio_cdev::Error implements From<std::io::Error>
so gpio_cdev::Error can be created using std::io::Error using into()
pub fn add_channel(&mut self, name: String, pin: u8) -> Result<(), gpio_cdev::Error> {
if pin > 20 {
let io_err = std::io::Error::new(std::io::ErrorKind::Other, format!("Pin {} is out of range!", pin));
return Err(io_err.into());
}
let line = self.chip.get_line(pin as u32)?;
...
}
I have a custom struct like the following:
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
Is it possible to get the number of struct fields programmatically (like, for example, via a method call field_count()):
let my_struct = MyStruct::new(10, "second_field", 4);
let field_count = my_struct.field_count(); // Expecting to get 3
For this struct:
struct MyStruct2 {
first_field: i32,
}
... the following call should return 1:
let my_struct_2 = MyStruct2::new(7);
let field_count = my_struct2.field_count(); // Expecting to get count 1
Is there any API like field_count() or is it only possible to get that via macros?
If this is achievable with macros, how should it be implemented?
Are there any possible API like field_count() or is it only possible to get that via macros?
There is no such built-in API that would allow you to get this information at runtime. Rust does not have runtime reflection (see this question for more information). But it is indeed possible via proc-macros!
Note: proc-macros are different from "macro by example" (which is declared via macro_rules!). The latter is not as powerful as proc-macros.
If this is achievable with macros, how should it be implemented?
(This is not an introduction into proc-macros; if the topic is completely new to you, first read an introduction elsewhere.)
In the proc-macro (for example a custom derive), you would somehow need to get the struct definition as TokenStream. The de-facto solution to use a TokenStream with Rust syntax is to parse it via syn:
#[proc_macro_derive(FieldCount)]
pub fn derive_field_count(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
// ...
}
The type of input is ItemStruct. As you can see, it has the field fields of the type Fields. On that field you can call iter() to get an iterator over all fields of the struct, on which in turn you could call count():
let field_count = input.fields.iter().count();
Now you have what you want.
Maybe you want to add this field_count() method to your type. You can do that via the custom derive (by using the quote crate here):
let name = &input.ident;
let output = quote! {
impl #name {
pub fn field_count() -> usize {
#field_count
}
}
};
// Return output tokenstream
TokenStream::from(output)
Then, in your application, you can write:
#[derive(FieldCount)]
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
MyStruct::field_count(); // returns 3
It's possible when the struct itself is generated by the macros - in this case you can just count tokens passed into macros, as shown here. That's what I've come up with:
macro_rules! gen {
($name:ident {$($field:ident : $t:ty),+}) => {
struct $name { $($field: $t),+ }
impl $name {
fn field_count(&self) -> usize {
gen!(#count $($field),+)
}
}
};
(#count $t1:tt, $($t:tt),+) => { 1 + gen!(#count $($t),+) };
(#count $t:tt) => { 1 };
}
Playground (with some test cases)
The downside for this approach (one - there could be more) is that it's not trivial to add an attribute to this function - for example, to #[derive(...)] something on it. Another approach would be to write the custom derive macros, but this is something that I can't speak about for now.