I try to create a simple application parsing command line arguments using clap library and converting them to a Config custom structure. I implemented From trait for my structure, however, when I try to call from function, I receive the following error:
the trait bound `minimal_example::Config: std::convert::From<cli::Opts>` is not satisfied
the following implementations were found:
<minimal_example::Config as std::convert::From<minimal_example::cli::Opts>>
required by `std::convert::From::from`
Here is the code:
main.rs:
mod cli;
use clap::Clap;
use minimal_example::Config;
fn main() {
println!("Hello, world!");
let opts = cli::Opts::parse();
let config = Config::from(opts);
}
cli.rs:
use clap::{Clap, crate_version};
/// This doc string acts as a help message when the user runs '--help'
/// as do all doc strings on fields
#[derive(Clap)]
#[clap(version = crate_version!(), author = "Yury")]
pub struct Opts {
/// Simple option
pub opt: String,
}
lib.rs:
mod cli;
pub struct Config {
pub opt: String,
}
impl From<cli::Opts> for Config {
fn from(opts: cli::Opts) -> Self {
Config {
opt: opts.opt,
}
}
}
cargo.toml:
[package]
name = "minimal_example"
version = "0.1.0"
authors = ["Yury"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = {version="3.0.0-beta.2", features=["wrap_help"]}
What am I doing wrong?
You have added mod cli to both lib.rs and main.rs.
They are different from the standpoint of each other.
Rust modules confusion when there is main.rs and lib.rs
may help in understanding that.
That's what the error says. It's satisfied for std::convert::From<minimal_example::cli::Opts> but not for std::convert::From<cli::Opts>.
A simple fix:
main.rs
mod cli;
use clap::Clap;
use minimal_example::Config;
impl From<cli::Opts> for Config {
fn from(opts: cli::Opts) -> Self {
Config {
opt: opts.opt,
}
}
}
fn main() {
println!("Hello, world!");
let opts = cli::Opts::parse();
let config = Config::from(opts);
}
Now std::convert::From<cli::Opts> is implemented for Config.
How you actually want to place all this depends on your package architecture.
Related
I have many lib crates and only one bin crate.
In the lib crates I have this simple code (different for each one):
use async_graphql::{Context, Object, Result};
use app::Services;
use std::sync::Arc;
#[derive(Default)]
pub struct PlayersQueryRoot;
#[Object]
impl PlayersQueryRoot {
async fn players_query_root(&self, ctx: &Context<'_>) -> Result<String> {
let res = ctx.data_unchecked::<Arc<Services>>(); // Services here is declared in `app` and imported with Cargo.toml, hence the issue
let player = res.player_by_id.handle(1).await?;
Ok(player.name)
}
}
In the bin crate (called app) I have this code:
use async_graphql::{EmptyMutation, EmptySubscription, Schema};
use graphql::{GraphqlSchema, QueryRoot};
use std::sync::Arc;
pub struct Services {
pub players: Arc<players::Service>,
pub user: Arc<user::Service>,
}
impl Services {
pub async fn new() -> Self {
Self {
user: Arc::new(user::new(/*some needed injection*/)),
players: Arc::new(players::new(/*some needed injection*/)),
}
}
}
//...
pub fn create_schema(services: Arc<Services>) -> GraphqlSchema {
Schema::build(QueryRoot::default(), EmptyMutation, EmptySubscription)
.data(services)
.finish()
}
It doesn't work because there is a cyclic dependency between app (bin crate) which has the lib crates as dependencies:
[dependencies]
players = { path = "../crates/players" }
users = { path = "../crates/users" }
Is there a way to fix this?
I have a library that is used through its rust interface by rust programs, as well as through C/C++ programs through generated cbindgen bindings, so I implemented a free function to free the string once the ffi function has used the string. However I want rust also to control the memory when it is used as a rust lib. How do I achieve this? is it even possible? or is calling the free function manually in rust the only option?
I also tried implementing drop, but that lead to this:
free(): double free detected in tcache 2
[1] 11097 IOT instruction cargo run
This block allows the string to be freed from C/C++, but the string is not freed in rust (valgrind shows definitely lost block). data is assigned using CString::into_raw()
use std::{ffi::CString, os::raw::c_char};
pub struct SomeData {
pub data: *const c_char
}
impl SomeData {
#[no_mangle] pub extern fn free_shared_string(&mut self) {
if !self.data.is_null() {
unsafe { CString::from_raw(self.data.cast_mut()); }
}
}
}
The docs for from_raw warn against doing exactly this.
Safety
This should only ever be called with a pointer that was earlier obtained by calling CString::into_raw. Other usage (e.g., trying to take ownership of a string that was allocated by foreign code) is likely to lead to undefined behavior or allocator corruption.
So do not use from_raw to pretend that a foreign string was allocated using Rust. If you just need to borrow it and let C free it, you should use the CStr type for borrowed strings. If you want to take ownership, you should copy it into a new string, or wrap it in a custom structure that has a Drop implementation capable of freeing the original memory.
You cannot have two different languages owning that memory. Rust is fundamentally built on a single-ownership model, so every piece of memory has a unique owner. There are some (intra-Rust) workarounds for that like Rc, but none of that will translate to C. So pick an owner, and make that language responsible for freeing the data.
The best solution for me was to have a separate feature, used when building the library to be used through C/C++ applications (ie. .a/.so) vs .rlib which cargo will build when included in a rust project through Cargo.toml.
This lets me use the same API from both possible application languages, call free from C/C++ on my string, and drop will free it in rust.
Note: the null character at the end is because the majority of the time my lib is used with C apps, hence storing with null for faster returns for them.
Add default-features = false when adding in Cargo.toml of a rust app.
lib.rs
use std::{ffi::{c_char, CStr, FromBytesWithNulError, CString}, mem::forget, str::Utf8Error, string::FromUtf8Error};
#[cfg(feature = "c-str")]
#[repr(C)]
pub struct SharedString {
str: *const c_char
}
#[cfg(not(feature = "c-str"))]
pub struct SharedString {
str: Vec<u8>
}
#[cfg(feature = "c-str")]
impl SharedString {
pub fn from_bytes(buf: &[u8]) -> Self {
let mut buf = buf.to_vec();
if let Some(c) = buf.last() {
if *c != 0 {
buf.push(0);
}
}
let s = Self { str: buf.as_ptr().cast() };
forget(buf);
s
}
pub unsafe fn get_string(&self) -> Result<String, SharedStringError> {
Ok(CStr::from_ptr(self.str).to_str()?.to_owned())
}
pub unsafe fn free(&self) {
if !self.str.is_null() {
let _ = CString::from_raw(self.str.cast_mut());
}
}
}
#[cfg(not(feature = "c-str"))]
impl SharedString {
pub fn from_bytes(buf: &[u8]) -> Self {
let mut buf = buf.to_vec();
if let Some(c) = buf.last() {
if *c != 0 {
buf.push(0);
}
}
Self { str: buf }
}
pub fn get_string(&self) -> Result<String, SharedStringError> {
let mut s = self.str.clone();
if let Some(c) = s.last() {
if *c == 0 {
s.pop();
}
}
String::from_utf8(s).map_err(|e| e.into())
}
// do nothing because rust vec will get dropped automatically
pub fn free(&self) {}
}
// Just for proof of concept
#[derive(Debug)]
pub enum SharedStringError {
NullError,
Utf8Error
}
impl From<FromBytesWithNulError> for SharedStringError {
fn from(_: FromBytesWithNulError) -> Self {
Self::NullError
}
}
impl From<Utf8Error> for SharedStringError {
fn from(_: Utf8Error) -> Self {
Self::Utf8Error
}
}
impl From<FromUtf8Error> for SharedStringError {
fn from(_: FromUtf8Error) -> Self {
Self::Utf8Error
}
}
Cargo.toml
[package]
name = "mylib"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[features]
default = ["c-str"]
c-str = []
I'm using the prost crate in a very "hello world" way, with a basic ProtoBuf file:
foo.proto
syntax = "proto3";
package foo;
message Foo {
string mystring = 1;
}
I can verify the types that prost produces at compile time by inspecting ./target/PROJECT/build/PROJECT-{some hash}/out/foo.rs:
foo.rs
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Foo {
#[prost(string, tag="1")]
pub mystring: ::prost::alloc::string::String,
}
See that the prost::Message trait gets derived? Its docs claim I have tons of functions at my disposal for this trait, but only the two required ones, encoded_len() and clear(), can be called without error. Any of the provided ones (those with default implementations) result in a cannot find function in this scope error.
main.rs
use prost::Message;
pub mod foo {
include!(concat!(env!("OUT_DIR"), "/foo.rs"));
}
fn main() {
let f = foo::Foo { mystring: "bar".to_string() };
let v = encode_to_vec(&f);
}
cargo run
error[E0425]: cannot find function `encode_to_vec` in this scope
|
| let v = encode_to_vec(&f);
| ^^^^^^^^^^^^^ not found in this scope
And, worryingly, this warning implies it's not even looking at the trait it needs to:
warning: unused import: prost::Message
(edit) For reference:
Cargo.toml
[package]
name = "testing"
version = "0.1.0"
edition = "2018"
[dependencies]
prost = { version = "0.7.0", features = ["std"] }
[build-dependencies]
prost-build = "0.7.0"
encode_to_vec is not a free function. You need to call it as one of
f.encode_to_vec()
foo::Foo::encode_to_vec(&f)
Message::encode_to_vec(&f)
<foo::Foo as Message>::encode_to_vec(&f)
The first method is the most normal, but the other ones may produce useful error messages when you get confused about what's going on.
[Edit:] Well, encode_to_vec was added in prost 0.8.0, so with 0.7.0, it won't be usable.
I'm currently using syn following an example to create an AST that can be mutated. I understand that I can modify the node I'm travesing (as shown below in my current code) but
I'm curious if I can add some code in between the current node and the next node. Is the syn crate capable of this?
use syn::visit_mut::{self, VisitMut};
use syn::Expr;
#[derive(Debug)]
struct MyStruct;
impl VisitMut for MyStruct {
fn visit_expr_mut(&mut self, node: &mut Expr) {
if let Expr::MethodCall(expr) = &node.to_owned() {
// I can modify the existing node like so:
*node = parse_quote!("// Hello World");
// How could I add something after this node and before the next?
}
}
}
pub fn create() {
let current_dir = std::env::current_dir().expect("Unable to get current directory");
let rust_file = std::fs::read_to_string(current_dir.join("src").join("lib.rs")).expect("Unable to read rust file");
let ast = syn::parse_file(&rust_file).expect("Unable to create AST from rust file");
MyStruct.visit_file_mut(&mut ast);
}
Edit to show use case:
The file I'm currently parsing looks like:
#[macro_use]
extern crate foo;
mod test;
fn init(handle: foo::InitHandle) {
handle.add_class::<Test::test>();
}
Let's say that when I read the AST, I want to add another mod and another handle for it like so:
#[macro_use]
extern crate foo;
mod test;
mod store;
fn init(handle: foo::InitHandle) {
handle.add_class::<Test::test>();
handle.add_class::<Store::store>();
}
As I commented, it highly depends on what you want to insert. Because you can't just insert anything before or after node easily.
For your specific case, you could use parse_quote! to produce an ExprBlock.
*node = parse_quote!(
{
#expr;
handle.add_class::<Store::store>();
}
);
Which with the following input:
fn init(handle: foo::InitHandle) {
handle.add_class::<Test::test>();
}
Would produce this output:
fn init(handle: foo::InitHandle) {
{
handle.add_class::<Test::test>();
handle.add_class::<Store::store>();
};
}
(Note I have reformatted the output, to be prettier)
Alternatively, you could override visit_block_mut() instead. That way you'd have access to stmts: Vec<Stmt>, and would be able to insert before and after a Stmt. The downside is that by doing it that way, you wouldn't be able to easily visit all Exprs, as by using visit_expr_mut().
I'm following an Iron web framework tutorial, which seemed pretty simple, but I can't seem to encode a struct as JSON.
extern crate iron;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use rustc_serialize::json;
struct Greeting {
msg: String,
}
fn main() {
fn hello_world(_: &mut Request) -> IronResult<Response> {
let greeting = Greeting { msg: "hello_world".to_string() };
let payload = json::encode(&greeting).unwrap();
// Ok(Response::with((status::Ok,payload)))
}
// Iron::new(hello_world).http("localhost:3000").unwrap();
}
My Cargo.toml
[package]
name = "iron_init"
version = "0.1.0"
authors = ["mazbaig"]
[dependencies]
iron = "*"
rustc-serialize = "*"
And my error:
error: the trait bound `Greeting: rustc_serialize::Encodable` is not satisfied [E0277]
let payload = json::encode(&greeting).unwrap();
^~~~~~~~~~~~
help: run `rustc --explain E0277` to see a detailed explanation
note: required by `rustc_serialize::json::encode`
I kinda get that the right types aren't getting passed into the json.encode() function, but I'm having trouble figuring out what it wants from me. I'm probably missing something really basic.
You didn't provide the actual tutorial that you are using, but it appears to match this one from brson.
extern crate iron;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use rustc_serialize::json;
#[derive(RustcEncodable)]
struct Greeting {
msg: String
}
fn main() {
fn hello_world(_: &mut Request) -> IronResult<Response> {
let greeting = Greeting { msg: "Hello, World".to_string() };
let payload = json::encode(&greeting).unwrap();
Ok(Response::with((status::Ok, payload)))
}
Iron::new(hello_world).http("localhost:3000").unwrap();
println!("On 3000");
}
Notice anything different between the two?
#[derive(RustcEncodable)]
struct Greeting {
msg: String
}
You have to specify that the Encodable trait is implemented. In this case, you can do so by deriving RustcEncodable.