Comments (20)
i made a similar workflow for my game-rs recently
uses a library to make a simple toml config and a config command which changes config as per needs with FuzzySelector menu
https://github.com/amanse/game-rs
i can make a quick pr, what will be the options in the config?
from anime-dl.
That would be wonderful, can you please wait for me to add the config first?
You can exclusively work on the command after that.
Note:
- toml
+ yaml
since it is more user friendly
from anime-dl.
yess, I'll be waiting
also if i could suggest something, you can use confy, it supports toml, yaml and json and handles the config part with no boilerplate and for all OSes
from anime-dl.
I have already written most of the boilerplate code either way, so its ok
from anime-dl.
@Amanse here is your plalyground :)
Go wild, I left some comments on how I want this to proceed, but I am open to suggestions.
from anime-dl.
One more request that I have is that before applying any change to the config, show a diff and prompt the user if they want to proceed.
from anime-dl.
nicee that's a great idea, I'll get right on it
from anime-dl.
Hey, did you have something specific in mind to iterate over the struct fields?
rust doesn't make it easy to dynamically update a field in a struct and serde(_aux) only gives name of field. making static update function for each field will be dumb
i can think of 2 ways it can go:
- either to Deserialize into a hashmap so we can change with key (selected by the user) [sub-fields will be hashmap inside hasmap]
- or use something like bevy_reflect which allows changing value with dynamic values but takes away some of the memory safety guarantees of rust
do you have any preference on which way to go or any other way you can think of?
from anime-dl.
rust doesn't make it easy to dynamically update a field in a struct and serde(_aux) only gives name of field. making static update function for each field will be dumb
I'll try and make a small prototype for that
from anime-dl.
yeah bevy_reflect looks like the way to go, or writing a trait and implementing it for every single structure in the config
actually, the latter sounds more safe and easy, ig ill take the L
from anime-dl.
yes, the latter is immensely more easy as per my limited experience with bevy_reflect
another way i can think is, since we can get an index and field name with serde safely, we can make a selection to enum mapper and make a function which takes a value and enum and just updates with match
it's the easiest option by far and updating this when config grows will be minimal
but will need a long ass match
trait will be prettier way to code doe, I'll give it a shot next
from anime-dl.
Ayo check this out
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=06f2842006c70215d1c4a81f780236dd
macros can change dynamically, when we add anything to config we just have to add a macro line, it can even handle different prompts for different types
from anime-dl.
Took me some time to learn procedural macros, btw what you linked is a declarative macro
Here I made an example of how this could work
module fake_reflect
Cargo.toml
Toggle
[package]
name = "fake_reflect"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "0.15"
quote = "0.6"
lib.rs
Toggle
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
use syn::{Data, DataStruct, DeriveInput, Fields, Ident};
fn impl_hello_world(ast: &DeriveInput) -> TokenStream {
let name = &ast.ident;
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
let field_name = fields.iter().map(|field| &field.ident);
let field_name2 = field_name.clone();
let field_name3 = field_name.clone();
let field_type = fields.iter().map(|field| &field.ty);
let enum_name = syn::parse_str::<Ident>(&format!("{}_field", name.to_string())).unwrap();
let enum_vars = fields.iter().map(|field| {
syn::parse_str::<syn::Path>(&format!("{}::{}", enum_name, field.ident.as_ref().unwrap()))
.unwrap()
});
TokenStream::from(quote! {
#ast
enum #enum_name {
#(
#field_name(#field_type),
)*
}
impl #name {
fn get(&self, field: impl ToString) -> anyhow::Result<#enum_name> {
match field.to_string().as_str() {
#(
stringify!(#field_name2) => Ok(#enum_vars(self.#field_name3)),
)*
_ => Err(anyhow::anyhow!("Unknown field.")),
}
}
}
})
}
#[proc_macro_attribute]
pub fn hello_world(args: TokenStream, input: TokenStream) -> TokenStream {
let _ = args;
// Parse the string representation
let ast = syn::parse_macro_input!(input as DeriveInput);
// Build and return the generated impl
impl_hello_world(&ast)
}
usage
Cargo.toml
Toggle
...
[dependencies]
fake_reflect = { path = "fake_reflect" }
...
main.rs
Toggle
#[macro_use]
extern crate fake_reflect;
pub fn main() {
#[fake_reflect::hello_world]
struct Waffles {
hello: i16,
}
let a = Waffles { hello: 42 };
match a.get("hello").unwrap() {
Waffles_field::hello(value) => println!("{}", value),
_ => (),
};
}
from anime-dl.
Here is the generated code from the above message:
pub fn main() {
struct Waffles {
hello: i16,
}
enum Waffles_field {
hello(i16),
}
impl Waffles {
fn get(&self, field: impl ToString) -> anyhow::Result<Waffles_field> {
match field.to_string().as_str() {
"hello" => Ok(Waffles_field::hello(self.hello)),
_ => Err(anyhow::anyhow!("Unknown field.")),
}
}
}
let a = Waffles { hello: 42 };
match a.get("hello").unwrap() {
Waffles_field::hello(value) => println!("{}", value),
_ => ()
};
}
PS: I used cargo expand
from anime-dl.
wow, took me some time to understand but this simplifies the whole process, rust macros are awesome lol
will make a pr asap
from anime-dl.
kinda under estimated rust borrow checker, String doesn't implement Copy strikes again, it may take some more time than i expected
from anime-dl.
kinda under estimated rust borrow checker, String doesn't implement Copy strikes again, it may take some more time than i expected
.clone()
from anime-dl.
i misunderstood what the error meant, working now, partially added the update method too
from anime-dl.
Update function working
Only need to loop over fields and call the function for selected field now
from anime-dl.
sorry i was in hospital for a few days
What i am stuck on is getting new value into proc macro, since field type needs to be iterated
and another method that is working is passing value with field enum that we get from the get method. But we cannot change value inside enum from original to new value without matching with each enum
i was looking into ways of doing it with serde and found this
use-serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize)]
struct ExampleStruct {
field_a: i32,
field_b: String,
}
fn main() {
let mut my_struct = ExampleStruct {
field_a: 42,
field_b: String::from("hello"),
};
let mut field_updates = HashMap::new();
field_updates.insert("field_a", 99);
field_updates.insert("field_b", String::from("world"));
for (field_name, field_value) in field_updates {
let field_name = field_name.to_string();
let field_value = serde_json::to_value(&field_value).unwrap();
let mut fields = my_struct.serialize().unwrap();
fields.remove(&field_name);
fields.insert(field_name, field_value);
my_struct = ExampleStruct::deserialize(fields).unwrap();
}
println!("Updated struct: {:?}", my_struct);
}
bevy_reflect seems a viable option too
from anime-dl.
Related Issues (5)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from anime-dl.