Return an arbitrary Encodable from a match expression? - serialization

I have a match expression than can return several (builtin and custom) types, which will ultimately be serialized to JSON and returned from a web request. I would prefer to avoid repeating the serialization code or making a string copy in each match arm.
Each arm returns an Encodable; however, it seems that Encodable is not object-safe, so I cannot make a pointer to it.
Edit: Due to changes in Rust, the question has gone from "Is this a good way to do this?" to "How can I do this at all?" (This is with version rustc 1.0.0-nightly (ed530d7a3 2015-01-16 22:41:16 +0000))
extern crate "rustc-serialize" as rustc_serialize;
use rustc_serialize::{json, Encodable};
#[derive(RustcEncodable)]
struct Valid {
value: u32
}
#[derive(RustcEncodable)]
struct Error {
error: &'static str // '
}
fn main() {
let valid = true;
let result = match valid {
true => Box::new(Valid { value: 42 }) as Box<Encodable>,
false => Box::new(Error { error: "bork" }) as Box<Encodable>
};
let mut buf = String::new();
result.encode(&mut json::Encoder::new(&mut buf)).unwrap();
println!("{}", buf);
}
error: cannot convert to a trait object because trait `rustc-serialize::serialize::Encodable` is not object-safe [E0038]

There are 2 ways in which traits can be used in Rust:
As bounds in generic functions (static dispatch)
As trait objects, behind pointers (dynamic dispatch)
Because Encodable is not object-safe, we can't use dynamic dispatch, because the compiler doesn't allow us to create a pointer to an Encodable.
Therefore, we have to use static dispatch. To do this, I've moved the code that works on the Encodable to a new, generic function, and called it from each arm.
extern crate "rustc-serialize" as rustc_serialize;
use rustc_serialize::{json, Encodable};
#[derive(RustcEncodable)]
struct Valid {
value: u32
}
#[derive(RustcEncodable)]
struct Error {
error: &'static str // '
}
fn do_encode<E: Encodable>(e: E) -> () {
let mut buf = String::new();
e.encode(&mut json::Encoder::new(&mut buf)).unwrap();
println!("{}", buf);
}
fn main() {
let is_valid = true;
match is_valid {
true => do_encode(Valid { value: 42 }),
false => do_encode(Error { error: "bork" }),
};
}

Related

How to return a Hash/Raku object from native call?

I am writing a library that uses NativeCall, it would be very convenient for me to be able to return a Raku Hash from an exported function. How can I do this?
For example, in Ruby, if I wanted to return a Hash from C, I would do something like:
#include "ruby.h"
VALUE make_hash() {
VALUE hash = rb_hash_new();
return hash;
}
I am interested to see if this can be done, I was thinking that maybe I would need to use a MoarVM header or something. But I'm not sure.
What I'm trying to do is write a C function that takes in a String does some stuff, then returns a Raku hash.
it would be very convenient for me to be able to return a Raku Hash from an exported function
A workaround could be to let the C function return a struct with key and values and then write a Raku wrapper that converts that into a Raku hash like this:
use v6;
use NativeCall;
constant LIB = ('./libmylib.so');
class HInfo is repr('CStruct') is export {
has Str $.key1;
has num64 $.value1;
has Str $.key2;
has num64 $.value2;
}
sub foo_(Str--> HInfo) is native(LIB) is symbol('foo') { * }
sub foo(Str $str --> Hash) {
my HInfo $hinfo = foo_($str);
my %h;
%h{$hinfo.key1} = $hinfo.value1;
%h{$hinfo.key2} = $hinfo.value2;
return %h;
}
my %h = foo("bar");
dd %h;
I have done roughly this for Rust over here (this is a collection of some Raku-Rust Nativecall code examples, not a module)...
First the raku:
## Rust FFI Omnibus: Objects
## http:##jakegoulding.com/rust-ffi-omnibus/objects/
class ZipCodeDatabase is repr('CPointer') {
sub zip_code_database_new() returns ZipCodeDatabase is native($n-path) { * }
sub zip_code_database_free(ZipCodeDatabase) is native($n-path) { * }
sub zip_code_database_populate(ZipCodeDatabase) is native($n-path) { * }
sub zip_code_database_population_of(ZipCodeDatabase, Str is encoded('utf8'))
returns uint32 is native($n-path) { * }
method new {
zip_code_database_new
}
submethod DESTROY { # Free data when the object is garbage collected.
zip_code_database_free(self);
}
method populate {
zip_code_database_populate(self)
}
method population_of( Str \zip ) {
zip_code_database_population_of(self, zip);
}
}
my \database = ZipCodeDatabase.new;
database.populate;
my \pop1 = database.population_of('90210');
my \pop2 = database.population_of('20500');
say pop1 - pop2;
Then the Rust:
// Rust FFI Omnibus: Objects
// http://jakegoulding.com/rust-ffi-omnibus/objects/
pub struct ZipCodeDatabase {
population: HashMap<String, u32>,
}
impl ZipCodeDatabase {
fn new() -> ZipCodeDatabase {
ZipCodeDatabase {
population: HashMap::new(),
}
}
fn populate(&mut self) {
for i in 0..100_000 {
let zip = format!("{:05}", i);
self.population.insert(zip, i);
}
}
fn population_of(&self, zip: &str) -> u32 {
self.population.get(zip).cloned().unwrap_or(0)
}
}
#[no_mangle]
pub extern "C" fn zip_code_database_new() -> *mut ZipCodeDatabase {
Box::into_raw(Box::new(ZipCodeDatabase::new()))
}
#[no_mangle]
pub extern "C" fn zip_code_database_free(ptr: *mut ZipCodeDatabase) {
if ptr.is_null() {
return;
}
unsafe {
Box::from_raw(ptr);
}
}
#[no_mangle]
pub extern "C" fn zip_code_database_populate(ptr: *mut ZipCodeDatabase) {
let database = unsafe {
assert!(!ptr.is_null());
&mut *ptr
};
database.populate();
}
#[no_mangle]
pub extern "C" fn zip_code_database_population_of(
ptr: *const ZipCodeDatabase,
zip: *const c_char,
) -> u32 {
let database = unsafe {
assert!(!ptr.is_null());
&*ptr
};
let zip = unsafe {
assert!(!zip.is_null());
CStr::from_ptr(zip)
};
let zip_str = zip.to_str().unwrap();
database.population_of(zip_str)
}
Obviously the C side of affairs will need to be quite different, but hopefully this gives enough clues.
As someone suggested, this is best done with a wrapper function. First things first though, what kind of value are you returning from C?
Your best bet is to return a CStruct.

Expected struct Config, found () while using process::exit

I'm new to Rust and going through the official book. I'm working on a simple grep example and want to make an exit function which I can use in different places. Unfortunately using this function in a closure in unwrap_or_else causes a compile error. This not clear to me why, because when I use the contents of the function directly in the closure it works.
Here is my main.rs file:
use std::env;
use std::fs;
use std::process;
use std::error::Error;
use std::fmt::Display;
struct Config{
query: String,
filename: String,
}
impl Config {
fn new(input: &[String]) -> Result<Config, &'static str> {
if input.len() < 3 {
return Err("Not enough arguments provided.");
}
let query = input[1].clone();
let filename = input[2].clone();
Ok(Config { query, filename })
}
}
fn run(cfg: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(&cfg.filename)?;
contents.find(&cfg.query).expect("Corrupted text file.");
Ok(())
}
fn exit<T: Display>(msg: &str, err: T) {
println!("{}: {}", msg, err);
process::exit(1);
}
fn main() {
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
let cfg = Config::new(&args).unwrap_or_else(|err| {
exit("Problem parsing arguments", err);
});
if let Err(err) = run(cfg) {
exit("Application error", err);
}
}
And here is the compile error:
error[E0308]: mismatched types
--> src\main.rs:41:55
|
41 | let cfg = Config::new(&args).unwrap_or_else(|err| {
| _______________________________________________________^
42 | | exit("Problem parsing arguments", err);
43 | | });
| |_____^ expected struct `Config`, found `()`
When I change the Config::new(&args).unwrap_or_else closure to this, it works:
let cfg = Config::new(&args).unwrap_or_else(|err| {
println!("Problem parsing arguments: {}", err);
process::exit(1);
});
I got stuck on this too. You need to import the process library:
use std::process;
edit: On second look you did import it. For others who run into this problem then that was mine. I got the same error.
You need to specify, that your exit() function never returns, i.e. add -> !.
These functions are called "diverging functions".
fn exit<T: Display>(msg: &str, err: T) -> ! {
println!("{}: {}", msg, err);
process::exit(1);
}
However, you should be careful with using process::exit(). Because it will terminate the current process, and not invoke destructors.
To ensure destructors are handled, you should instead do something like this:
fn main() {
std::process::exit(match run() {
Ok(_) => 0,
Err(code) => code,
});
}
fn run() -> Result<(), i32> {
// Application logic here, i.e. what you'd otherwise have had in `main()`
Ok(())
}
The example is a minor adapted version of the one found at the documentation for process::exit().
To add to vallentin's answer here's the more idiomatic version which doesn't use process::exit:
use std::env;
use std::error::Error;
use std::fmt::Display;
use std::fs;
use std::process;
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(input: &[String]) -> Result<Config, &'static str> {
if input.len() < 3 {
return Err("Not enough arguments provided.");
}
let query = input[1].clone();
let filename = input[2].clone();
Ok(Config { query, filename })
}
}
fn run(cfg: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(&cfg.filename)?;
// convert Option to a Result so we can use `?`
contents.find(&cfg.query).ok_or("Corrupted text file.")?;
Ok(())
}
// you can return a Result from main and Rust will
// print the error to the user if there is one
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
// use `?` instead of `exit` function
let cfg = Config::new(&args)?;
run(cfg)?;
Ok(())
}
playground

How do I return a Result containing every error from an iterator of Results, not just the first one?

I'm trying to implement a simple interpreter in Rust, for which I have created a Tokens struct, which takes source characters and produces either a Token or a ScanError inside a Result:
pub struct Tokens<'src> {
chars: Chars<'src>,
}
impl<'src> Iterator for Tokens<'src> {
type Item = Result<Token, ScanError>;
fn next(&mut self) -> Option<Result<Token, ScanError>> {
// ...
}
}
Since Result implements FromIterator, it is simple to collect the result to either the first ScanError or a vector of Tokens:
fn scan_tokens(source: &str) -> Result<Vec<Token>, ScanError> {
let iter = Tokens {
chars: source.chars(),
};
iter.collect()
}
In the case of multiple errors I really want to return every error:
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
// what goes here?
}
It isn't possible as far as I know to implement my own version of FromIterator because neither that trait or Result are local to my crate. Can anyone suggest a clean way of doing this?
I have written an implementation using partition on the iterator, then unwrapping each Result, below, but it's not fun to read and doesn't feel like good use of iterators:
type T = Vec<Result<Token, ScanError>>;
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
let iter = Tokens {
chars: source.chars(),
};
let (tokens_results, error_results): (T, T) = iter.partition(|result| result.is_ok());
let errors: Vec<ScanError> = error_results
.into_iter()
.map(|result| result.unwrap_err())
.collect();
if errors.len() > 0 {
return Err(errors);
}
Ok(tokens_results
.into_iter()
.map(|result| result.unwrap())
.collect())
}
unwrapping each Result
I would use itertools' partition_map to avoid the need to unwrap:
use itertools::{Either, Itertools}; // 0.8.0
fn iterator() -> impl Iterator<Item = Result<i32, bool>> {
vec![Ok(1), Err(false), Ok(2), Err(true), Ok(3)].into_iter()
}
fn example() -> Result<Vec<i32>, Vec<bool>> {
let (values, errors): (Vec<_>, Vec<_>) = iterator().partition_map(|v| match v {
Ok(v) => Either::Left(v),
Err(e) => Either::Right(e),
});
if errors.is_empty() {
Ok(values)
} else {
Err(errors)
}
}
See also:
What's the most idiomatic way of working with an Iterator of Results?
How do I stop iteration and return an error when Iterator::map returns a Result::Err?
How do I perform iterator computations over iterators of Results without collecting to a temporary vector?
You could also use the fact that Option and Result implement IntoIterator to avoid the exact unwrap, although this still processes one collection twice:
fn example2() -> Result<Vec<i32>, Vec<bool>> {
let (values, errors): (Vec<_>, Vec<_>) = iterator().partition(|result| result.is_ok());
if errors.is_empty() {
Ok(values.into_iter().flat_map(Result::ok).collect())
} else {
Err(errors.into_iter().flat_map(Result::err).collect())
}
}
See also:
Why does `Option` support `IntoIterator`?
An imperative solution is often the most expressive and efficient way to implement some algorithm. It's Rust, not Haskell; not everything needs to be functional.
fn scan_tokens(source: &str) -> Result<Vec<Token>, Vec<ScanError>> {
let iter = Tokens {
chars: source.chars(),
};
let mut tokens = Vec::new();
let mut errors = Vec::new();
for result in iter {
match result {
Ok(token) => {
tokens.push(token);
}
Err(e) => {
errors.push(e);
}
}
}
if errors.is_empty() {
Ok(tokens)
} else {
Err(errors)
}
}

Wrong number of lifetime parameters when using a modified `Chars` iterator

I want to implement the IntoIterator trait for a struct containing a String. The iterator is based on the chars() iterator, is supposed to count the '1' chars and accumulate the result. This is a simplified version of what I got so far:
use std::iter::Map;
use std::str::Chars;
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in str_struct {
println!("{}", a);
}
}
struct StringStruct {
system_string: String
}
impl IntoIterator for StringStruct {
type Item = u32;
type IntoIter = Map<Chars, Fn(char) -> u32>;
fn into_iter(self) -> Self::IntoIter {
let count = 0;
return self.system_string.chars().map(|c| match c {
Some('1') => {
count += 1;
return Some(count);
},
Some(chr) => return Some(count),
None => return None
});
}
}
Expected output: 1, 2, 2, 3
This fails with:
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/main.rs:17:25
|
17 | type IntoIter = Map<Chars, Fn(char) -> u32>;
| ^^^^^ expected 1 lifetime parameter
The chars iterator should have the same lifetime as the StringStruct::system_string, but I have no idea how to express this or if this approach is viable at all.
To answer the question you asked, I'd recommend to impl IntoIterator for &StringStruct (a reference to a StringStruct instead of the struct directly). The code would look like this:
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = Map<Chars<'a>, Fn(char) -> u32>;
// ...
}
However, you will notice many more errors that have a different origin afterwards. The next error that pops up is that Fn(char) -> u32 does not have a constant size at compile time.
The problem is that you try to name the type of your closure by writing Fn(char) -> u32. But this is not the type of your closure, but merely a trait which is implemented by the closure. The type of a closure can't be named (sometimes called "Voldemort type").
This means that, right now, you can't specify the type of a Map<_, _> object. This is a known issue; the recently accepted impl Trait-RFC might offer a workaround for cases like this. But right now, it's not possible, sorry.
So how to solve it then? You need to create your own type that implements Iterator and use it instead of Map<_, _>. Note that you can still use the Chars iterator. Here is the full solution:
struct StringStructIter<'a> {
chars: Chars<'a>,
count: u32,
}
impl<'a> Iterator for StringStructIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next().map(|c| {
if c == '1' {
self.count += 1;
}
self.count
})
}
}
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = StringStructIter<'a>;
fn into_iter(self) -> Self::IntoIter {
StringStructIter {
chars: self.system_string.chars(),
count: 0,
}
}
}
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in &str_struct {
println!("{}", a);
}
}
And just a small note: an explicit return when not necessary is considered bad style in Rust. Better stick to rule and write idiomatic code by removing return whenever possible ;-)

Changing a enum's field in Rust

I am very new to Rust but I am trying to work out how to modify an instance of an enum. I need to use managed boxes for other reasons, but it seems to make changing an enum's field hard.
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let mut state = #A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
I get the error cannot borrow immutable anonymous field as mutable. The mut seems to only say that state, the variable, is mutable. I want to tell Rust the whole thing is mutable. I find forced immutability one of the most annoying things of Rust.
Some time ago managed boxed had their own "hierarchy" of mutability. The following code used to work then:
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let state = #mut A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
But managed boxes are scheduled to be removed from the language. In current version of Rust #mut is not a valid token. You have to use RefCell, a mutable cell which provides mutability inside managed pointers. Currently it looks somewhat like this:
#[feature(managed_boxes)];
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
let state = #RefCell::new(A(123));
{
let mut r = state.borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
}
println!("{:?}", state)
}
You will get rather extensive output on the terminal though, because it will print internals of RefCell structure. See documentation on std::cell module for more information on cells and how to use them.
In the future Rust won't have special syntax for managed boxes at all. Garbage collection will be implemented in libraries. I believe the code will look like this (Rust authors, please correct me if I'm wrong):
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
// state is of type Gc<RefCell<State>>
let state = box(Gc) RefCell::new(A(123));
// Dereference will work for library pointer types, not sure about autodereference
let mut r = (*state).borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
println!("{:?}", *state)
}