The documentation has got me confused. I'm kind of stuck on how to get matches from a parser derived struct. How would I go about doing this? Here's what my argument struct looks like.
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
/// Host address
#[clap(short, long)]
pub host: String,
/// Database username
#[clap(short, long)]
pub username: String,
/// Database password
#[clap(short='P', long)]
pub password: String,
/// Database name
#[clap(short='d', long)]
pub database: String,
/// Database port number
#[clap(short, long, default_value_t = 3306)]
pub port: u32,
}
The clap::Parser trait has a method parse that you can use, that will read the arguments into a structure of the type, or exit the process on error.
use clap::Parser;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
/// Host address
#[clap(short, long)]
pub host: String,
...
}
fn main() {
let args = Args::parse();
println!("got host: {}", args.host);
}
Related
I need to serialize a struct from a remote crate and all of the fields in the struct are private. There are getter's implemented in the remote struct to get those values. I am following this guidance and got it to work just fine for primitive types. However, I'm struggling with how to implement this for non-primitive types (ie: String) that the remote struct contains.
Below is a small piece of what I've implemented to frame the issue. The DataWrapper struct simply wraps Data, where Data is the remote struct.
#[derive(Serialize)]
pub struct DataWrapper {
#[serde(with = "DataDef")]
pub data: Data,
}
#[derive(Serialize)]
#[serde(remote = "remote_crate::data::Data")]
pub struct DataDef {
#[serde(getter = "Data::image_id")] // This works
image_id: u16,
#[serde(getter = "Data::description")] // This does not work
description: String,
}
The error I get when compiling this is
#[derive(Serialize)]
^^^^^^^^^ expected struct `std::string::String`, found `&str`
This makes sense, since the getter Data::description returns &str rather than a String. But, I'm not seeing a way in my code to coerce this so the compiler is happy.
If I change DataDef::description to be &str instead of String, then I have to implement lifetimes. But, when I do that, the compiler then says the remote "struct takes 0 lifetime arguments".
Appreciate any tips on how I can serialize this and other non-primitive types.
One approach you could do, so that you have full control of the serialization. Is to have the data wrapper be a copy of the struct fields you need, instead of the entire remote struct. Then you can implement From<remote_crate::data::Data> for DataWrapper and use serde without trying to coerce types.
#[derive(Serialize)]
pub struct Data {
image_id: u16,
description: String,
}
impl From<remote_crate::data::Data> for Data {
fn from(val: remote_crate::data::Data) -> Self {
Self {
image_id: val.image_id,
description: val.description.to_string(),
}
}
}
// Then you could use it like this:
// let my_data: Data = data.into();
I couldn't get it to work with an &str, but if you're OK with an allocation, you can write a custom getter:
mod local {
use super::remote::RemoteData;
use serde::{Deserialize, Serialize};
fn get_owned_description(rd: &RemoteData) -> String {
rd.description().into()
}
#[derive(Serialize)]
#[serde(remote = "RemoteData")]
pub struct DataDef {
#[serde(getter = "get_owned_description")]
description: String,
}
}
mod remote {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct RemoteData {
description: String,
}
impl RemoteData {
pub fn description(&self) -> &str {
&self.description
}
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9c7c0b069d7e16b6faac2fa2b840c72
If I have a struct I need Default implemented on, if all the field's types have Default implemented themsevles, then I can use the derive macro, otherwise I need to implement Default manually. However, there are some situations where I have a large struct where almost all the fields would be derivable, except there is a small number of fields with types which do not have Default implemented, and I can impl myself because the type is external. This ends up with the situation in the below example. I would prefer to avoid this as it means I need to keep the fields in sync between two places, which is more time consuming, error prone, and verbose. I'm hoping there might be some syntactical suagr to avoid this, but I'm new to rust and can't think of any. I'm thinking something like:
impl Default for Data2 {
fn default() -> Self {
Self {
external_data: ExternalType::One,
..Default::default(),
}
}
}
Example
#[derive(Default)]
struct Data {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
}
enum ExternalType {
One,
Two,
}
// #[derive(Default)]
struct Data2 {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
external_data: ExternalType,
}
impl Default for Data2 {
fn default() -> Self {
Self {
name: Default::default(),
flag: Default::default(),
selected: Default::default(),
show_reference: Default::default(),
index: Default::default(),
create_name: Default::default(),
create_type: Default::default(),
external_data: ExternalType::One,
}
}
}
I think the smart-default crate can handle this. It lets you derive SmartDefault, which derives Default for all fields except those with a #[default(my_default_value)] attribute.
Example:
use smart_default::SmartDefault;
#[derive(SmartDefault)]
enum Foo {
Bar,
#[default]
Baz {
#[default = 12]
a: i32,
b: i32,
#[default(Some(Default::default()))]
c: Option<i32>,
#[default(_code = "vec![1, 2, 3]")]
d: Vec<u32>,
#[default = "four"]
e: String,
},
Qux(i32),
}
There's also the more general derivative crate which lets you customize how all derives work, not just Default, but is a tad more verbose (because it's more general).
Example:
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default)]
pub struct RegexOptions {
pub pats: Vec<String>,
#[derivative(Default(value="10 * (1 << 20)"))]
pub size_limit: usize,
#[derivative(Default(value="2 * (1 << 20)"))]
pub dfa_size_limit: usize,
pub case_insensitive: bool,
pub multi_line: bool,
pub dot_matches_new_line: bool,
pub swap_greed: bool,
pub ignore_whitespace: bool,
#[derivative(Default(value="true"))]
pub unicode: bool,
}
As with most Orphan rule problems the only option available is the New Type pattern but I'm not sure this is really an improvement over a manual default impl.
struct ExternalWithDefault(ExternalType);
impl Default for ExternalWithDefault {
fn default() -> Self {
Self(ExternalType::One)
}
}
...
#[derive(Default)]
struct Data2 {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
external_data: ExternalWithDefault,
}
I have a project where I have a struct that looks like this:
pub struct Msg1Sender {
c_u: Vec<u8>,
secret: StaticSecret,
X_u: PublicKey,
static_secret: EphemeralSecret,
static_public: PublicKey,
APPEUI : Eui64,
kid: Vec<u8>,
auth: [u8; 64], //remove
}
that is constructeed like this:
impl PartyU<Msg1Sender> {
pub fn new(
c_u: Vec<u8>,
ecdh_secret: [u8; 32],
stat_priv: EphemeralSecret,
stat_pub: PublicKey,
APPEUI : Eui64,
kid: Vec<u8>,
) -> PartyU<Msg1Sender> {
// From the secret bytes, create the DH secret
let secret = StaticSecret::from(ecdh_secret);
// and from that build the corresponding public key
let X_u = PublicKey::from(&secret);
// Combine the authentication key pair for convenience
let mut auth = [0; 64]; //remove
PartyU(Msg1Sender {
c_u,
secret,
X_u,
static_secret:stat_priv,
static_public:stat_pub,
APPEUI,
kid,
auth //slettes
})
}
...
and then I have the following code in another file:
let msg1_sender =
PartyU::new(u_c_u, u_priv, v_static_priv, v_static_pub,APPEUI, u_kid);
println!("{:?}", msg1_sender.APPEUI);
Where I am trying to print a field on the struct.
This I can not do. I get the error:
no field `APPEUI` on type `oscore::edhoc::PartyU<oscore::edhoc::api::Msg1Sender>`
unknown field
help: one of the expressions' fields has a field of the same name: `0.`
Adding pub keywords to the fields I am trying to access makes no difference
Which makes no sense to me. the field exists. Why is this happening?
EDIT
I can now understand that the type I am trying to access is of type
PartyU<oscore::edhoc::api::Msg1Sender>
My mistake.
But If I now try to access the msgsender object by writing:
msg1_sender.0.APPEUI
It still fails with:
field `0` of struct `oscore::edhoc::PartyU` is private
Which again is strange to me, since the struct is public:
pub struct PartyU<S: PartyUState>(S);
// Necessary stuff for session types
pub trait PartyUState {}
impl PartyUState for Msg1Sender {}
impl PartyUState for Msg2Receiver {}
//impl PartyUState for Msg2Verifier {}
//impl PartyUState for Msg3Sender {}
/// Contains the state to build the first message.
pub struct Msg1Sender {
c_u: Vec<u8>,
secret: StaticSecret,
x_u: PublicKey,
static_secret: EphemeralSecret,
static_public: PublicKey,
pub APPEUI : Eui64,
kid: Vec<u8>,
auth: [u8; 64], //remove
}
impl PartyU<Msg1Sender> {
What part is it that I need to mark as public?
PartyU is a struct tuple, so in order to access the inner struct you have to access with .0.
Then after that, the Error code is clear:
field 0 of struct oscore::edhoc::PartyU is private
unless marked as pub, struct attributes are private and can only be accessed from the structs current module. You have to options to make them publicly available:
pub makes it public for any scope
pub(crate) makes it public for the crate where the struct lives in
pub struct PartyU(pub Msg1Sender);
pub struct Msg1Sender {
pub c_u: Vec<u8>,
pub secret: StaticSecret,
pub X_u: PublicKey,
pub static_secret: EphemeralSecret,
pub static_public: PublicKey,
pub APPEUI : Eui64,
pub kid: Vec<u8>,
pub auth: [u8; 64], //remove
}
I have struct from which I want to extract the data.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunResult {
pub runs: Vec<RunDetails>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunDetails {
pub details: String,
pub name: String,
pub id: String,
pub type: String,
}
I am getting the data which got inserted in above struct in the variable result which I am iterating below
let my_result:RunResult = result
.runs
.into_iter()
.filter(|line| line.details.contains(&"foo"))
.collect();
I am getting the error as
value of type `RunResult` cannot be built from `std::iter::Iterator<Item=RunDetails>`
I want to get the record where type=OK, details contains foo with highest id.
How can I achieve this?
Check out the documentation for collect here.
Your struct RunResult should implement FromIterator<RunDetails>.
Try adding this (untested by me):
impl FromIterator<RunDetails> for RunResult {
fn from_iter<I: IntoIterator<Item=RunDetails>>(iter: I) -> Self {
Self {
runs: Vec::from_iter(iter);
}
}
}
I have a Message struct which have a field I want to modify when calling a method on it.
This Message struct have an attachments field, which is an Option<Vec<Attachment>>.
My goal is to be able to call a method on Message to push an Attachment object to the attachments Vec.
#[derive(Debug, Serialize, Deserialize)]
pub struct Message {
/// The verified sender email address
#[serde(rename = "FromEmail")]
pub from_email: String,
/// The name of the sender
#[serde(rename = "FromName")]
pub from_name: String,
/// The subject of the email
#[serde(rename = "Subject")]
pub subject: Option<String>,
/// The raw text content of the email
#[serde(rename = "Text-part")]
pub text_part: String,
/// The HTML content of the email
#[serde(rename = "Html-part")]
pub html_part: Option<String>,
#[serde(rename = "Recipients")]
pub recipients: Vec<Recipient>,
#[serde(rename = "Attachments")]
pub attachments: Option<Vec<Attachment>>,
#[serde(rename = "Inline_attachments")]
pub inline_attachments: Option<Vec<InlineAttachments>>,
}
The following is my current implementation on the method that will push Attachment objects to the Option<Vec<Attachment>>:
pub fn attach(&mut self, attachment: Attachment) {
// if theres no attachments already
// initialize the attachments vector
if self.attachments.is_none() {
let mut attachments = Vec::new();
attachments.push(attachment);
self.attachments = Some(attachments);
} else {
// Where this is invalid as theres no `clone` for `Option<Vec<Attachment>>`
let attachments = self.attachments.clone();
attachments.push(attachment);
}
}
This is the implementation for the Attachment struct:
use serde::{Deserialize, Serialize};
/// An email attachment
#[derive(Debug, Serialize, Deserialize)]
pub struct Attachment {
#[serde(rename = "Content-type")]
pub content_type: String,
#[serde(rename = "Filename")]
pub filename: String,
pub content: String,
}
The issue is on the else block, where the attachents Option field is unwrapped, then an attachment object is pushed to the Vec.
The problem is that Attachment is unable to implement the Copy trait.
Which is the correct approach for scenarios like this in Rust?
Thanks in advance!
Option has a wide variety of helper methods which can help here. You basically want to mutate the Vec that's already there if there is one, and if not, create one and mutate it. You can do that with Option::get_or_insert_with, which returns a &mut Vec<Attachment>. With that, you can push the item onto the end. A minimal compilable example looks like this:
pub struct Message {
pub attachments: Option<Vec<Attachment>>,
}
#[derive(Debug)]
pub struct Attachment {
pub content_type: String,
pub filename: String,
pub content: String,
}
impl Message {
pub fn attach(&mut self, attachment: Attachment) {
self.attachments
.get_or_insert_with(Vec::new)
.push(attachment);
}
}
fn main() {
let mut m = Message { attachments: None };
let a = Attachment {
content_type: "application/json".into(),
filename: "foo.json".into(),
content: "{}".into(),
};
m.attach(a);
assert_eq!(m.attachments.unwrap()[0].content, "{}");
}
If you're using is_some or is_none (or, for Result, is_ok or is_err) in an if-else situation, that's usually an indication that you may want to rethink what you're doing, since that's not usually very idiomatic in Rust. Oftentimes, there's a helper method that does what you want in a simpler, easier to use way.