I'm writing an HTTP server in the actix_web framework using the tokio runtime and tokio-stream utilities. I would like to send some data (actix::web::Bytes) from a broadcast channel in a response. I also want to do some other stuff, so I'd like to write a wrapper implementing the MessageBody trait that at some point forwards the .poll_next() method. The problematic code looks like this:
use actix_web::web::Bytes;
use actix_web::body::{BodyStream, MessageBody};
use tokio_stream::wrappers::BroadcastStream;
use futures_core::stream::Stream;
// ...
struct Wrapper {
// some other stuff
broad_rx: BodyStream<BroadcastStream<broadcast::Receiver<Bytes>>>
}
impl MessageBody for Wrapper {
type Error = BroadcastStreamRecvError;
fn size(&self) -> actix_web::body::BodySize {
BodySize::Stream
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Result<Bytes, Self::Error>>> {
/*
do some other stuff
*/
self.broad_rx.poll_next(cx) // XXX the problem
}
}
This snippet doesn't compile and returns the following error:
error[E0599]: no method named `poll_next` found for struct `BodyStream` in the current scope
--> crates/demo/src/server.rs:***:***
|
*** | self.broad_rx.poll_next(cx)
| ^^^^^^^^^ method not found in `BodyStream<BroadcastStream<tokio::sync::broadcast::Receiver<actix_web::web::Bytes>>>`
I expect BodyStream to implement MessageBody and thus the .poll_next() method. because of this impl and the following chain of implementations:
Bytes implements:
Clone
Send
I'm not sure how to deduce whether it has a 'static lifetime in this context, as it's not a reference. If the lifetime isn't 'static I'd assume that is the problem, but I also don't know how to solve it. However, I'd also assume that the compiler would mention something about lifetimes if that is the case.
BroadcastStream<Bytes> implements:
Stream, if Bytes is 'static + Clone + Send. Item = Result<Bytes, BroadcastStreamRecvError> in that case.
BroadcastStreamRecvError implements:
Error and via this blanket implementation presumably also Into<Box<dyn Error + 'static, Global>>
BodyStream<Bytes> implements:
MessageBody because the Stream bound is satisfied by BroadcastStream<Bytes> and the 'static + Into<Box<dyn Error + 'static, Global>> is satisfied by
BroadcastStreamRecvError (except those pesky 'static requirements again)
Yet the error suggests, that one of the implementations doesn't apply for whatever reason. In fact even if I replace
broad_rx: BodyStream<BroadcastStream<broadcast::Receiver<Bytes>>>
with
broad_rx: BroadcastStream<broadcast::Receiver<Bytes>>
I still get an error saying that the .poll_next() method doesn't exist, despite the fact that this type should implement Stream.
How can I implement the MessageBody wrapper or further debug this?
The presented code has three problems preventing it from being compiled. The one causing the given error is caused by the problem put forth by #kmdreko. The reason why Pin is needed is a bit complicated and can be found in the async rust book. In a superficial way: If you want to use a .poll method then the thing needs to be pinned. One of the ways to solve this problem is using the pin-project crate that simplifies the creation of projections (helper functions used to access fields of pinned structs). Otherwise, one can write their own projections manually, like in this article.
The declaration then looks like this:
#[pin_project]
struct Wrapper {
#[pin]
broad_rx: BroadcastStream<broadcast::Receiver<Bytes>>,
}
and the projection that presents the pinned field (see further below) can be obtained like so:
let this = self.project();
This still doesn't compile, but for a trivial reason. First of all, the BodyStream is not needed at all, because the MessageBody is being manually implemented anyway. Secondly, the generic type of BroadcastStream isn't supposed to be the wrapped type (also because the wrapped type will always be broadcast::Receiver<_>), but the type returned from the channel. The following code compiles:
struct Wrapper {
broad_rx: BroadcastStream<Bytes>
}
impl MessageBody for Wrapper {
type Error = BroadcastStreamRecvError;
fn size(&self) -> actix_web::body::BodySize {
BodySize::Stream
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Result<Bytes, Self::Error>>> {
let this = self.project();
this.broad_rx.poll_next(cx)
}
}
Related
I'm trying to imbed Lua into Rust using Mlua. Using its guided tour, I successfully loaded and evaluated a chunk of Lua code. My next goal is to combine this with opening a file and reading its contents. This is where things get problematic:
use anyhow::Result;
use mlua::{Lua, UserData};
use std::fs;
pub struct LuaManager {
lua_state: Lua
}
impl LuaManager {
pub fn new() -> Self {
LuaManager {
lua_state: Lua::new(),
}
}
pub fn eval<T>(&self, chunk: &str) -> Result<T> where T: Clone + UserData {
let v = self.lua_state.load(chunk).eval::<T>()?;
Ok(v)
}
}
Since scripts can return literally anything, I thought a trait-locked generic annotation would solve the issue: The problem is this:
Error generated by rustc: the parameter type `T` may not live long enough... so that the type `T` will meet its required lifetime bounds...
For reference, here is the function signature as defined in lua.rs:
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R>
I don't understand why I'm having this issue. I've looked this up and this question pertained to user-created types, which to my knowledge I'm not doing... so what is the problem here? It's clear that things like <i32> won't die anytime soon. Cargo did suggest adding a static lifetime annotation, but doing some research into it points me to trying to solve the problem without using it first, since in 99% of cases you actually can get away without it.
Unfortunately in this case it seems like 'static is really required.
Lua::load() takes &'lua self and returns Chunk<'lua, '_>. Chunk::<'lua, '_>::eval::<R>() requires R: FromLuaMulti<'lua>. FromLuaMulti<'lua> is implemented for T: FromLua<'lua>. FromLua<'lua> is implemented for T: UserData, however it requires T: 'static (and also T: Clone, but this is irrelevant).
I've worked down a real-life example in a web app, which I've solved using unnecessary heap allocation, to the following example:
// Try replacing with (_: &String)
fn make_debug<T>(_: T) -> impl std::fmt::Debug {
42u8
}
fn test() -> impl std::fmt::Debug {
let value = "value".to_string();
// try removing the ampersand to get this to compile
make_debug(&value)
}
pub fn main() {
println!("{:?}", test());
}
As is, compiling this code gives me:
error[E0597]: `value` does not live long enough
--> src/main.rs:9:16
|
5 | fn test() -> impl std::fmt::Debug {
| -------------------- opaque type requires that `value` is borrowed for `'static`
...
9 | make_debug(&value)
| ^^^^^^ borrowed value does not live long enough
10 | }
| - `value` dropped here while still borrowed
I can fix this error in at least two ways:
Instead of passing in a reference to value in test(), pass in value itself
Instead of the parameter T, explicitly state the type of the argument for make_debug as &String or &str
My understanding of what's happening is that, when there is a parameter, the borrow checker is assuming that any lifetime on that parameter affects the output impl Debug value.
Is there a way to keep the code parameterized, continue passing in a reference, and get the borrow checker to accept it?
I think this is due to the rules around how impl trait opaque types capture lifetimes.
If there are lifetimes inside an argument T, then an impl trait has to incorporate them. Additional lifetimes in the type signature follow the normal rules.
For more information please see:
https://github.com/rust-lang/rust/issues/43396#issuecomment-349716967
https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#lifetime-parameters
https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#assumption-3-there-should-be-an-explicit-marker-when-a-lifetime-could-be-embedded-in-a-return-type
https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#scoping-for-type-and-lifetime-parameters
A more complete answer
Original goal: the send_form function takes an input parameter of type &T which is rendered to a binary representation. That binary representation is owned by the resulting impl Future, and no remnant of the original &T remains. Therefore, the lifetime of &T need not outlive the impl Trait. All good.
The problem arises when T itself, additionally, contains references with lifetimes. If we were not using impl Trait, our signature would look something like this:
fn send_form<T>(self, data: &T) -> SendFormFuture;
And by looking at SendFormFuture, we can readily observe that there is no remnant of T in there at all. Therefore, even if T has lifetimes of its own to deal with, we know that all references are used within the body of send_form, and never used again afterward by SendFormFuture.
However, with impl Future as the output, we get no such guarantees. There's no way to know if the concrete implementation of Future in fact holds onto the T.
In the case where T has no references, this still isn't a problem. Either the impl Future references the T, and fully takes ownership of it, or it doesn't reference it, and no lifetime issues arise.
However, if T does have references, you could end up in a situation where the concrete impl Future is holding onto a reference stored in the T. Even though the impl Future has ownership of the T itself, it doesn't have ownership of the values referenced by the T.
This is why the borrow check must be conservative, and insist that any references inside T must have a 'static lifetime.
The only workaround I can see is to bypass impl Future and be explicit in the return type. Then, you can demonstrate to the borrow checker quite easily that the output type does not reference the input T type at all, and any references in it are irrelevant.
The original code in the actix web client for send_form looks like:
https://docs.rs/awc/0.2.1/src/awc/request.rs.html#503-522
pub fn send_form<T: Serialize>(
self,
value: &T,
) -> impl Future<
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
Error = SendRequestError,
> {
let body = match serde_urlencoded::to_string(value) {
Ok(body) => body,
Err(e) => return Either::A(err(Error::from(e).into())),
};
// set content-type
let slf = self.set_header_if_none(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
);
Either::B(slf.send_body(Body::Bytes(Bytes::from(body))))
}
You may need to patch the library or write your own function that does the same thing but with a concrete type. If anyone else knows how to deal with this apparent limitation of impl trait I'd love to hear it.
Here's how far I've gotten on a rewrite of send_form in awc (the actix-web client library):
pub fn send_form_alt<T: Serialize>(
self,
value: &T,
// ) -> impl Future<
// Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
// Error = SendRequestError,
) -> Either<
FutureResult<String, actix_http::error::Error>,
impl Future<
Item = crate::response::ClientResponse<impl futures::stream::Stream>,
Error = SendRequestError,
>,
> {
Some caveats so far:
Either::B is necessarily an opaque impl trait of Future.
The first param of FutureResult might actually be Void or whatever the Void equivalent in Rust is called.
Is it ok practice to have this style Result?
fn a() -> Result<u32, &'static str>
And then what is the purpose of the Error trait? https://doc.rust-lang.org/std/error/trait.Error.html
Is an impl Error Result better practice?
impl Error for MyError {..... }
fn a() -> Result<u32, MyError>
In short: No, it's not okay. String as error throws away information about details and cause, making errors useless for callers as they won't be able to inspect and possibly recover from it.
In case you just need to fill Error parameter with something, create a unit struct. It's not much useful, but it's also not as volative as string. And you can easily distinguish foo::SomeError from bar::SomeError.
#[derive(Debug)]
pub struct SomeError; // No fields.
In case you can enumerate error variants, use enum.
It is also sometimes useful to "include" other errors into it.
#[derive(Debug)]
pub enum PasswordError {
Empty,
ToShort,
NoDigits,
NoLetters,
NoSpecials
}
#[derive(Debug)]
pub enum ConfigLoadError {
InvalidValues,
DeserializationError(serde::de::Error),
IoError(std::io::Error),
}
Nobody stops you from using structs.
They're particularly useful when you intentionaly want to hide some information from caller (In contrast to enums whose variants always have public visibility). E.g. caller has nothing to do with error message, but can use kind to handle it:
pub enum RegistrationErrorKind {
InvalidName { wrong_char_idx: usize },
NonUniqueName,
WeakPassword,
DatabaseError(db::Error),
}
#[derive(Debug)]
pub struct RegistrationError {
message: String, // Private field
pub kind: RegistrationErrorKind, // Public field
}
impl Error - existential type - makes no sense here. You can't return different error types with it in error place, if this was your intent. And opaque errors are not much useful, just like strings.
std::error::Error trait ensures that your SomeError type has implementation for std::fmt::{Display, Debug} (For displaying error to user and developer, correspondingly) and provides some useful methods like source (This returns the cause of this error); is, downcast, downcast_ref, downcast_mut. Last 4 are for error type erasure.
Error type erasure
Error type erasure has it's tradeoffs, but it's also worth mentioning.
It's also especially useful when writing somewht high-level application code. But in case of libraries you should think twice before deciding to use this approach, because it will make your library unusable with 'no_std'.
Say you have some function with non-trivial logic that can return values of some error types, not exactly one. In this case you can use (But don't abuse) error type erasure:
use std::error::Error;
use std::fmt;
use std::fs;
use std::io::Error as IoError;
use std::net::AddrParseError;
use std::net::Ipv4Addr
use std::path::Path;
// Error for case where file contains '127.0.0.1'
#[derive(Debug)]
pub struct AddressIsLocalhostError;
// Display implementation is required for std::error::Error.
impl fmt::Display for AddressIsLocalhostError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Address is localhost")
}
}
impl Error for AddresIsLocalhostError {} // Defaults are okay here.
// Now we have a function that takes a path and returns
// non-localhost Ipv4Addr on success.
// On fail it can return either of IoError, AddrParseError or AddressIsLocalhostError.
fn non_localhost_ipv4_from_file(path: &Path) -> Result<Ipv4Addr, Box<dyn Error + 'static>> {
// Opening and reading file may cause IoError.
// ? operator will automatically convert it to Box<dyn Error + 'static>.
// (via From trait implementation)
// This way concrete type of error is "erased": we don't know what's
// in a box, in fact it's kind of black box now, but we still can call
// methods that Error trait provides.
let content = fs::read_to_string(path)?;
// Parsing Ipv4Addr from string [slice]
// may cause another error: AddressParseError.
// And ? will convert it to to the same type: Box<dyn Error + 'static>
let addr: Ipv4Addr = content.parse()?;
if addr == Ipv4Add::new(127, 0, 0, 1) {
// Here we perform manual conversion
// from AddressIsLocalhostError
// to Box<dyn Error + 'static> and return error.
return Err(AddressIsLocalhostError.into());
}
// Everyhing is okay, returning addr.
Ok(Ipv4Addr)
}
fn main() {
// Let's try to use our function.
let maybe_address = non_localhost_ipv4_from_file(
"sure_it_contains_localhost.conf"
);
// Let's see what kind of magic Error trait provides!
match maybe_address {
// Print address on success.
Ok(addr) => println!("File was containing address: {}", addr),
Err(err) => {
// We sure can just print this error with.
// println!("{}", err.as_ref());
// Because Error implementation implies Display implementation.
// But let's imagine we want to inspect error.
// Here deref coercion implicitly converts
// `&Box<dyn Error>` to `&dyn Error`.
// And downcast_ref tries to convert this &dyn Error
// back to &IoError, returning either
// Some(&IoError) or none
if Some(err) = err.downcast_ref::<IoError>() {
println!("Unfortunately, IO error occured: {}", err)
}
// There's also downcast_mut, which does the same, but gives us
// mutable reference.
if Some(mut err) = err.downcast_mut::<AddressParseError>() {
// Here we can mutate err. But we'll only print it.
println!(
"Unfortunately, what file was cantaining, \
was not in fact an ipv4 address: {}",
err
);
}
// Finally there's 'is' and 'downcast'.
// 'is' comapres "erased" type with some concrete type.
if err.is::<AddressIsLocalhostError>() {
// 'downcast' tries to convert Box<dyn Error + 'static>
// to box with value of some concrete type.
// Here - to Box<AddressIsLocalhostError>.
let err: Box<AddressIsLocalhostError> =
Error::downcast(err).unwrap();
}
}
};
}
To summarize: errors should (I'd say - must) provide useful information to caller, besides ability to just display them, thus they should not be strings. And errors must implement Error at least to preserve more-less consistent error handling experience across all crates. All the rest depends on situation.
Caio alredy mentioned The Rust Book.
But these links might be also useful:
std::any module level API documentation
std::error::Error API documentation
For simple use-cases, a opaque error type like Result<u32, &'static str> or Result<u32, String> is enough but for more complex libraries, it is useful and even encouraged to create your own error type like a struct MyError or enum AnotherLibError, which helps you to define better your intentions. You may also want to read the Error Handling chapter of the Rust by Example book.
The Error trait, as being part of std, helps developers in a generic and centralized manner to define their own error types to describe what happened and the possible root causes (backtrace). It is currently somewhat limited but there are plans to help to improve its usability.
When you use impl Error, you are telling the compiler that you don't care about the type being returned, as long it implements the Error trait. This approach is useful when the error type is too complex or when you want to generalize over the return type. E.g.:
fn example() -> Result<Duration, impl Error> {
let sys_time = SystemTime::now();
sleep(Duration::from_secs(1));
let new_sys_time = SystemTime::now();
sys_time.duration_since(new_sys_time)
}
The method duration_since returns a Result<Duration, SystemTimeError> type but in the above method signature, you can see that for the Err part of the Result, it is returning anything that implements the Error trait.
Summarizing everything, if you read the Rust book and know what you are doing, you can choose the approach that best fits your needs. Otherwise, it is best to define your own types for your errors or use some third-party utilities like the error-chain or failure crates.
Trying to get dynamic dispatch working in a trait static method but get a type must be known error.
I'm trying to achieve something like
F#
https://github.com/Thorium/SimpleCQRS-FSharp/blob/master/CommandSide/Domain.fs
C#
https://github.com/gregoryyoung/m-r/blob/master/SimpleCQRS/Domain.cs..
Is the only way to make the trait generic?
pub struct Aggregate<T: AggregateRoot>
{
pub id: Uuid,
agg: T,
changes: Vec<Box<Any>>
}
impl <T :AggregateRoot > Aggregate<T>
{
fn GetUncomittedChanges(&self) -> Vec<Box<Any>> { self.changes}
fn MarkChangesAsCommitted(&self) { self.changes.drain(..);}
}
trait AggregateRoot
{
fn new2() -> Self; //should be private
fn new(id: Uuid) -> Self;
fn LoadsFromHistory(changes : Vec<Box<Any>> ) -> Self
where Self: Sized
{
let newAgg = AggregateRoot::new2 ();
changes.iter().map( |e| newAgg.Apply(e) );
newAgg.MarkChangesAsCommitted();
newAgg
}
fn Apply<U: Any>(&self, arg: U) ;
fn GetId(&self) -> Uuid;
}
currently trying but gives 2 params expected 1 supplied.
Let's start with issues in how you asked the question, in the hopes that you will be able to ask better questions in the future. The complete error you are getting is:
<anon>:27:37: 27:52 error: the type of this value must be known in this context
<anon>:27 changes.iter().map( |e| newAgg.Apply(e) );
^~~~~~~~~~~~~~~
Note that the compiler error message shows you exactly which bit of code is at fault. It's useful to include that error when asking a question.
You've also included extraneous detail. For example, GetUncomittedChanges, id and GetId are all unused in your example. When solving a problem, you should produce an MCVE. This helps you understand the problem better and also allows people helping you to look at less code which usually results in faster turnaround.
Your code has a number of problems, but let's start at the first error:
let newAgg = AggregateRoot::new2 ();
This says "for any possible AggregateRoot, create a new one". Many concrete types can implement a trait (which is the point of traits), but the compiler needs to know how much space to allocate for a given instance. There might be a struct that takes 1 byte or 200 bytes; how much space needs to be allocated on the stack in this case?
To progress, you can use Self::new2 instead. That means to create a new instance of the current implementor.
The next error is
<anon>:20:16: 20:40 error: no method named `MarkChangesAsCommitted` found for type `Self` in the current scope
<anon>:20 newAgg.MarkChangesAsCommitted();
^~~~~~~~~~~~~~~~~~~~~~~~
You are calling a method on a concrete type from a trait implementation; this simply doesn't make any sense. What would happen if a bool implements this trait? It doesn't have a MarkChangesAsCommitted method. I don't know what you intended in this case, so I'll just delete it.
Now you get this error:
<anon>:19:9: 19:16 error: `changes` does not live long enough
<anon>:19 changes.iter().map( |e| newAgg.Apply(e) );
^~~~~~~
note: reference must be valid for the static lifetime...
<anon>:17:5: 21:6 note: ...but borrowed value is only valid for the scope of parameters for function at 17:4
That's because your method Apply expects to be given a type that implements Any. However, you are passing a &Box<Any>. Any has a lifetime bound of 'static, and that reference is not static. A straightforward change is to accept a reference to a type that implements Any:
fn Apply<U: Any>(&self, arg: &U);
Now that the code compiles, there's a number of stylistic issues to fix:
no space before :
no space after >
no space before (
no space inside ()
map should not be used for side effects
function and variable names are camel_case
most of the time, accept a &[T] instead of a Vec<T> as a function argument.
use "Egyptian" braces, except when you are using a where clause.
All together, your code looks like:
use std::any::Any;
struct Aggregate<T: AggregateRoot> {
agg: T,
changes: Vec<Box<Any>>
}
impl<T: AggregateRoot> Aggregate<T> {
fn mark_changes_as_committed(&self) { }
}
trait AggregateRoot {
fn new() -> Self;
fn load_from_history(changes: &[Box<Any>]) -> Self
where Self: Sized
{
let new_agg = Self::new();
for change in changes { new_agg.apply(change) }
new_agg
}
fn apply<U: Any>(&self, arg: &U);
}
fn main() {}
Is there a way to constrain the concrete types of the AggregateRoot to Aggregates so mark_changes can be called?
Not that I'm aware of. It sounds like you want to move mark_changes to the trait and force all implementors of the trait to implement it:
trait AggregateRoot {
fn load_from_history(changes: &[Box<Any>]) -> Self
where Self: Sized
{
let new_agg = Self::new();
for change in changes { new_agg.apply(change) }
new_agg.mark_changes_as_committed();
new_agg
}
fn mark_changes_as_committed(&self);
// ...
}
I am caught between two different issues/bugs, and can't come up with a decent solution. Any help would be greatly appreciated
Context, FFI, and calling a lot of C functions, and wrapping C types in rust structs.
The first problem is ICE: this path should not cause illegal move.
This is forcing me to do all my struct-wrapping using & references as in:
pub struct CassResult<'a> {
result:&'a cql_ffi::CassResult
}
Instead of the simpler, and preferable:
pub struct CassResult {
result:cql_ffi::CassResult
}
Otherwise code like:
pub fn first_row(&self) -> Result<CassRow,CassError> {unsafe{
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
}}
Will result in:
error: internal compiler error: this path should not cause illegal move
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, I go ahead and wrap everything using lifetime managed references, and all is not-horrible until I try to implement an iterator. At which point I see no way around this problem.
method next has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter
So given those two conflicting issues, I am totally stuck and can't find any way to implement a proper rust iterator around a FFI iterator-like construct.
Edit: With Shep's suggestion, I get:
pub struct CassResult {
pub result:cql_ffi::CassResult
}
and
pub fn get_result(&mut future:future) -> Option<CassResult> {unsafe{
let result:&cql_ffi::CassResult = &*cql_ffi::cass_future_get_result(&mut future.future);
Some(CassResult{result:*result})
}}
but then get:
error: cannot move out of borrowed content
Some(CassResult{result:*result}
Is there any way to make that pattern work? It's repeated all over this FFI wrapping code.
Only a partial answer: use the "streaming iterator" trait and macro.
I have had a similar problem making Rust bindings around the C mysql API. The result is code like this, instead of native for syntax:
let query = format!("SELECT id_y, value FROM table_x WHERE id = {}", id_x);
let res = try!(db::run_query(&query));
streaming_for!( row, res.into_iter(), {
let id_y: usize = try!(row.convert::<usize>(0));
let value: f64 = try!(row.convert::<f64>(1));
});
Here res holds the result and frees memory on drop. The lifetime of row is tied to res:
/// Res has an attached lifetime to guard an internal pointer.
struct Res<'a>{ p: *mut c_void }
/// Wrapper created by into_iter()
struct ResMoveIter<'a>{ res: Res<'a> }
impl<'a> /*StreamingIterator<'a, Row<'a>> for*/ ResMoveIter<'a>{
/// Get the next row, or None if no more rows
pub fn next(&'a mut self) -> Option<Row<'a>>{
...
}
}
#[unsafe_destructor]
impl<'a> Drop for Res<'a>{
fn drop(&mut self){
...
}
}
To answer my own question. The only decent answer was a way around the original ICE, but as thepowersgang comments, the correct way to do this now is to use :std::ptr::read, so using that approach, no ICE, and hopefully progress.