I want to use the clap derive API in order to parse an Ipv4Addr.
#![allow(unused)]
use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(short, long, parse(from_str))]
ip_dst: Ipv4Addr,
}
fn main() {
let args = Args::parse();
}
My attempt gives the following error even though Ipv4Addr seems to implement FromStr which provides from_str
error[E0277]: the trait bound `Ipv4Addr: From<&str>` is not satisfied
--> src/main.rs:10:31
|
10 | #[clap(short, long, parse(from_str))]
| ^^^^^^^^ the trait `From<&str>` is not implemented for `Ipv4Addr`
|
= help: the following implementations were found:
<Ipv4Addr as From<[u8; 4]>>
<Ipv4Addr as From<u32>>
For more information about this error, try `rustc --explain E0277`.
My Questions are:
Why isn't the method provided by FromStr used?
How can I fix the program to do what I want?
What you want is what is used by default (since Ipv4Addr implements FromStr), without specifiying any parse option:
use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(short, long)]
ip_dst: Ipv4Addr,
}
Playground
Otherwise, you need to use try_from_str as per the example:
#![allow(unused)]
use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(short, long, parse(try_from_str))]
ip_dst: Ipv4Addr,
}
Playground
Ipv4Addr implements FromStr but not From<&str> which is the From trait with &str as a parameter. If you want to use FromStr, specify parse(try_from_str) or omit it since it's the default.
Update for Clap v4
use clap::{arg, value_parser, Command}; // Clap v4
use std::net::Ipv4Addr;
fn main() {
let matches = Command::new("clap-test")
.arg(
arg!(--ip <VALUE>)
.default_value("127.0.0.1")
.value_parser(value_parser!(Ipv4Addr)),
)
.get_matches();
println!(
"IP {:?}",
matches.get_one::<Ipv4Addr>("ip").expect("required"),
);
}
Related
I am using rust diesel diesel = { version = "1.4.8", features = ["postgres","64-column-tables","chrono","serde_json"] } to do the group by query follow the docs like this:
fpub fn get_bill_book_account_sum(){
use crate::diesel::GroupByDsl;
use diesel::dsl::max;
use crate::model::diesel::dict::dict_schema::test as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::id)
.select((max(bill_record_table::tags),bill_record_table::id))
.filter(bill_record_table::dsl::tags.eq(9));
}
then compile this code, shows error like this:
error[E0277]: the trait bound `aggregate_ordering::max::max<BigInt, columns::tags>: NonAggregate` is not satisfied
--> src/main.rs:19:17
|
19 | .select((max(bill_record_table::tags),bill_record_table::id))
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonAggregate` is not implemented for `aggregate_ordering::max::max<BigInt, columns::tags>`
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `diesel::Expression` for `(aggregate_ordering::max::max<BigInt, columns::tags>, columns::id)`
note: required by a bound in `diesel::QueryDsl::select`
--> /Users/xiaoqiangjiang/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/diesel-1.4.8/src/query_dsl/mod.rs:291:20
|
291 | Selection: Expression,
| ^^^^^^^^^^ required by this bound in `diesel::QueryDsl::select`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust-learn` due to previous error
where am I doing wrong? what should I do to fixed this problem? this is the schema define(I have removed all the columns just using 2 columns to make a minimal reproduce example):
table! {
test (id) {
id -> Int8,
tags -> Int8,
}
}
and this is the model define:
// Generated by diesel_ext
#![allow(unused)]
#![allow(clippy::all)]
use std::io::Write;
use diesel::deserialize::FromSql;
use diesel::pg::Pg;
use diesel::serialize::{Output, ToSql};
use diesel::sql_types::Jsonb;
use rocket::serde::Serialize;
use serde::Deserialize;
use crate::model::diesel::dict::dict_schema::*;
#[derive(Queryable,Debug,Serialize,Deserialize,Default)]
pub struct Test {
pub id: i64,
pub tags: i64,
}
this is the minimal main.rs entrypoint:
#[macro_use]
extern crate diesel;
mod model;
use diesel::{ ExpressionMethods, QueryDsl};
fn main() {
get_bill_book_account_sum();
}
pub fn get_bill_book_account_sum(){
use crate::diesel::GroupByDsl;
use diesel::dsl::max;
use crate::model::diesel::dict::dict_schema::test as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::id)
.select((max(bill_record_table::tags),bill_record_table::id))
.filter(bill_record_table::dsl::tags.eq(9));
}
change the aggregate query like this fixed this problem:
pub fn get_bill_book_account_sum(request: &BillAccountRequest) -> Result<Vec<(i64, i32)>, diesel::result::Error>{
use crate::diesel::GroupByDsl;
use crate::model::diesel::fortune::fortune_schema::bill_record as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::account_id)
.select((diesel::dsl::sql::<diesel::sql_types::BigInt>("SUM(CAST(amount AS Integer))"),bill_record_table::account_id))
.filter(bill_record_table::dsl::bill_book_id.eq(request.bill_book_id));
let result = source_query.load::<(i64,i32)>(&get_connection());
return result;
}
the solution come from this issue. This is the answer come from the maintainer that shows diesel 1.x did not support group by official.
I want to accept a std::time::Duration on a command line. I'm using clap with #[derive(Parser)] to generate the parameter parser. Is there any way I can directly accept an input, rather than accepting a number and doing the conversion later?
Something like this:
#[derive(Debug, Parser)]
pub struct Config {
#[clap( ??? )]
interval: std::time::Duration,
}
Clap 3.0:
To do custom parsing, you should use #[clap(parse(try_from_str = ...))] and define a custom function to parsing the argument. Here's an example:
use clap::Parser;
#[derive(Debug, Parser)]
pub struct Config {
#[clap(parse(try_from_str = parse_duration))]
interval: std::time::Duration,
}
fn parse_duration(arg: &str) -> Result<std::time::Duration, std::num::ParseIntError> {
let seconds = arg.parse()?;
Ok(std::time::Duration::from_secs(seconds))
}
Clap 4.0:
Almost same as above; the helper function can stay the same, but the attribute syntax has changed:
use clap::Parser;
#[derive(Debug, Parser)]
pub struct Config {
#[arg(value_parser = parse_duration)]
interval: std::time::Duration,
}
fn parse_duration(arg: &str) -> Result<std::time::Duration, std::num::ParseIntError> {
let seconds = arg.parse()?;
Ok(std::time::Duration::from_secs(seconds))
}
This parsing is pretty limited (I don't know what format you'd expect the duration to be in), but it shows how you'd do it.
If you want to be flexible with your duration arguments, consider using a crate like humantime; their Duration can be used with clap without special attributes since it implements FromStr.
Compact version for Clap 4
use clap::Parser;
use std::time::Duration;
use std::num::ParseIntError;
#[derive(Debug, Parser)]
pub struct Config {
#[arg(value_parser = |arg: &str| -> Result<Duration, ParseIntError> {Ok(Duration::from_secs(arg.parse()?))})]
interval_secs: Duration,
}
I don't think there's a way to differentiate a u8 or whatever from a std::time::Duration on the command line itself. That said, you should be able to do something like this if you implement FromStr for Duration:
struct Config {
#[structopt(short = "i", long = "interval")]
interval: std::time::Duration,
}
But it definitely seems easier to take something like a u8 and do a conversion in main() or similar.
I want to build a parser for a generic struct by serde_json, here is the simplifed logic. And it will generate an error: "src does not live long enough".
But why this would cause a not-long-enough lifetime error?
Is there any way to fix it, or it is simply not recommended to write codes like this?
use serde_json;
use serde::Deserialize;
use std::marker::PhantomData;
#[derive(Default)]
struct Parser<'de, P:Deserialize<'de>>{
phantom1: PhantomData<&'de ()>,
phantom2: PhantomData<P>,
}
impl<'de, P:Deserialize<'de>> Parser<'de,P>{
fn parse(&self, src:&'de String){
serde_json::from_str::<P>(&src).unwrap();
}
}
#[derive(Default)]
struct OutterParser<'de, P:Deserialize<'de>>{
parser: Parser<'de, P>
}
impl<'de, P:Deserialize<'de>> OutterParser<'de,P>{
fn read_and_parse(&self){
let src = String::from(r#""""#);
self.parser.parse(&src);
}
}
fn main(){
let parser = OutterParser::<String>::default();
parser.read_and_parse();
}
Here is the rust playground link
Edit:
Thanks for the answer from Kevin. I once thought that 'de lifetime would be automatically derived to be a lifetime in the local parse function. After P struct been built from local &src, the src can be dropped.
Now I know the lifetime of function arguments would be less than 'de without evident annotation.
But if the function signature is revised to fn parse(&self, &'de str), the 'de will be further propagated upwards, which is not what I want.
P: Deserialize<'de> means that deserializing into a value of type P requires input data which must live for at least 'de.
fn parse(&self, src:String){
serde_json::from_str::<P>(&src).unwrap();
Instead, you provided a reference to the local variable src which will be dropped at the end of the parse function, and therefore definitely lives shorter than 'de.
In order to not have this problem, you must define parse such that it accepts a reference that is valid for 'de:
fn parse(&self, src: &'de str) {
Found answer in another question :)
How to return the result of serde_json::from_str when called with a String that will be dropped at the end of the function?
An easier workaround is to use DeserializeOwned...
use serde_json;
use serde::de::DeserializeOwned;
use std::marker::PhantomData;
#[derive(Default)]
struct Parser<P:DeserializeOwned>{
phantom2: PhantomData<P>,
}
impl<P:DeserializeOwned> Parser<P>{
fn parse(&self, src:&String){
serde_json::from_str::<P>(&src).unwrap();
}
}
#[derive(Default)]
struct OutterParser<P:DeserializeOwned>{
parser: Parser<P>
}
impl<P:DeserializeOwned> OutterParser<P>{
fn read_and_parse(&self){
let src = String::from(r#""""#);
self.parser.parse(&src);
}
}
fn main(){
let parser = OutterParser::<String>::default();
parser.read_and_parse();
}
Wondering if there's a "proper" way of converting an Enum to a &str and back.
The problem I'm trying to solve:
In the clap crate, args/subcommands are defined and identified by &strs. (Which I'm assuming don't fully take advantage of the type checker.) I'd like to pass a Command Enum to my application instead of a &str which would be verified by the type-checker and also save me from typing (typo-ing?) strings all over the place.
This is what I came up with from searching StackOverflow and std:
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Command {
EatCake,
MakeCake,
}
impl FromStr for Command {
type Err = ();
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"eat-cake" => Ok(Self::EatCake),
"make-cake" => Ok(Self::MakeCake),
_ => Err(()),
}
}
}
impl<'a> From<Command> for &'a str {
fn from(c: Command) -> Self {
match c {
Command::EatCake => "eat-cake",
Command::MakeCake => "make-cake",
}
}
}
fn main() {
let command_from_str: Command = "eat-cake".to_owned().parse().unwrap();
let str_from_command: &str = command_from_str.into();
assert_eq!(command_from_str, Command::EatCake);
assert_eq!(str_from_command, "eat-cake");
}
And here's a working playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b5e9ac450fd6a79b855306e96d4707fa
Here's an abridged version of what I'm running in clap.
let matches = App::new("cake")
.setting(AppSettings::SubcommandRequiredElseHelp)
// ...
.subcommand(
SubCommand::with_name(Command::MakeCake.into())
// ...
)
.subcommand(
SubCommand::with_name(Command::EatCake.into())
// ...
)
.get_matches();
It seems to work, but I'm not sure if I'm missing something / a bigger picture.
Related:
How to use an internal library Enum for Clap Args
How do I return an error within match statement while implementing from_str in rust?
Thanks!
The strum crate may save you some work. Using strum I was able to get the simple main() you have to work without any additional From implementations.
use strum_macros::{Display, EnumString, IntoStaticStr};
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Display, EnumString, IntoStaticStr)] // strum macros.
pub enum Command {
#[strum(serialize = "eat-cake")]
EatCake,
#[strum(serialize = "make-cake")]
MakeCake,
}
fn main() {
let command_from_str: Command = "eat-cake".to_owned().parse().unwrap();
let str_from_command: &str = command_from_str.into();
assert_eq!(command_from_str, Command::EatCake);
assert_eq!(str_from_command, "eat-cake");
}
I have my types defined and then I keep them in something like ArrayVec<[MyType, 16]> (from arrayvec crate) variables (members of a structure). Restson has the RestPath trait, allow us to define a path used to form a URI when performing a REST query.
However, due to the restriction that only local traits can be implemented for arbitrary types (AKA the orphan rule) I can't use it straightforwardly for ArrayVec<[MyType, 16]>.
I somehow overcame the problem by implementing the trait for ~specialization~ instantiation of the following enum:
enum ModelArray<T> {
Array(T)
}
and then decorticate the instance of T using:
type MyArray = ModelArray<ArrayVec<[MyType; 16]>>;
let encapsulated_array: MyArray = client.get(()).unwrap();
let ModelArray::<ArrayVec<[MyType; 16]>>::Array(myarray) = encapsulated_array;
This works as minimal example, but I suffer from the fact I cannot call client.get(()).unwrap() directly to the member of other structure.
I'm surprised full specialization of a generic type isn't treated by Rust as local type and orphan rule still applies. Why?
Are there other nice ways to overcome the limitation and would let me nicely assign result of Restson's get() into members of a structure?
Working code:
extern crate restson;
extern crate arrayvec;
extern crate serde_derive;
use restson::RestPath;
use arrayvec::ArrayVec;
#[derive(Deserialize, Debug)]
struct MyType {
id: u16,
data: u32,
}
struct DataModel {
my_data: ArrayVec<[MyType; 16]>
}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum ModelArray<T> {
Array(T)
}
impl RestPath<u16> for MyType {
fn get_path(id: u16) -> Result<String, Error> {
Ok(format!("data/MyType/{}", id))
}
}
impl RestPath<()> for ModelArray<ArrayVec<[MyType; 16]>> {
fn get_path(_: ()) -> Result<String, Error> {
Ok(String::from("data/MyType"))
}
}
use restson::RestClient;
pub fn load_data() {
let mut client = RestClient::new(&format!("http://{}", "localhost:8080")).unwrap();
let element: Type = client.get(24).unwrap();
println!("Room: {:?}", elementh);
type ModelArray = ModelArray<ArrayVec<[MyType; 16]>>;
let encapsulated: ModelArray = client.get(()).unwrap();
let ModelArray::<ArrayVec<[MyType; 16]>>::Array(elements) = encapsulated;
println!("Room: {:?}", elements[0]);
}
On Rust Playground (lack of restson crate wouldn't allow you to build)
Respective complete code: on GitHubGist