Searching for a nice "to and from binary slice" abstraction


#1

I have the following thing that I’m searching a nice abstraction for: in leveldb (http://github.com/skade/leveldb), keys handled as ptr+length (slice). But they may represent complex data, e.g. encoding a key and it’s type.

Previously, I used a hand-rolled trait for that:

/// this is very old-school
pub trait Key {
  fn from_u8(key: &[u8]) -> Self;
  fn as_slice<T, F: Fn(&[u8]) -> T>(&self, f: F) -> T;
}

I now try to express it through convert:

pub trait Key<'a> : From<&'a [u8]> + AsRef<[u8]>

Now, I have the problem of a very unwieldy lifetime. Is there any way to avoid this?

Preferably, easy implementations for all integer types would be great, which isn’t possible with From, as integer types are defined in a another crate.


#2

I think you want for<'a>. But take my solution with a grain of salt, this is the first time I have used for<'a>, I’ve seen it quite a few times though.

PlayPen

pub trait Key: for<'a> From<&'a [u8]> + AsRef<[u8]> {}

struct MyKey (Vec<u8>);

impl<'a> From<&'a [u8]> for MyKey {
    fn from(s: &'a [u8]) -> MyKey {
        MyKey(s.iter().map(|&c| c).collect())
    }
}

impl AsRef<[u8]> for MyKey {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl Key for MyKey {}

fn main() {
}

#3

That sounds like what I want to express. Thanks! :slight_smile:


#4

Is trait ... for documented somewhere?


#5

Level 2: From and AsRef are implemented in libcore and some of the types I’d like to allow as keys as well. So implementing From<&'a [u8]> is not possible for i32.

Problem is: I am unable to find a clean way around this. I tried implementing my own From and AsRef traits that would be automatically implemented if there is an existing implementation, but this doesn’t seem to work:

use std::convert;

pub trait From<T> {
    fn from(T) -> Self;
}

impl<T> From<T> for convert::From<T> {
    #[inline]
    fn from(input: T) -> Self {
        convert::From::from(input)
    }
}
src/lib.rs:7:21: 7:37 error: the trait `core::convert::From` cannot be made into an object [E0372]
src/lib.rs:7 impl<T> From<T> for convert::From<T> {

#6
use std::convert;

pub trait From<T> {
    fn from(T) -> Self;
}

impl<T, X> From<T> for X where X: convert::From<T> {
    #[inline]
    fn from(input: T) -> Self {
        convert::From::from(input)
    }
}

Something like that?


#7

If it would work:

src/lib.rs:12:1: 17:2 error: conflicting implementations for trait `From` [E0119]
src/lib.rs:12 impl<T, X> From<T> for X where X: convert::From<T> {
src/lib.rs:13     #[inline]
src/lib.rs:14     fn from(input: T) -> Self {
src/lib.rs:15         convert::From::from(input)
src/lib.rs:16     }
src/lib.rs:17 }
src/lib.rs:19:1: 24:2 note: note conflicting implementation here
src/lib.rs:19 impl<'a> From<&'a [u8]> for &'a [u8] {
src/lib.rs:20     #[inline]
src/lib.rs:21     fn from(input: &'a [u8]) -> &'a [u8] {
src/lib.rs:22         input
src/lib.rs:23     }
src/lib.rs:24 }
src/lib.rs:35:1: 35:30 error: the trait `for<'a> core::convert::From<&'a [u8]>` is not implemented for the type `&'a [u8]` [E0277]

This is interesting, as &[u8] does not implement From<&a [u8]>, if I remove my own implementation:

src/lib.rs:35:1: 35:30 error: the trait `for<'a> core::convert::From<&'a [u8]>` is not implemented for the type `&'a [u8]` [E0277]
src/lib.rs:35 impl<'a> Key for &'a [u8] { }
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Which it should, as:

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

I created a playpen out of this: http://is.gd/oiUh5M


#8

Logically Key should have a lifetime for whatever it references, in addition, implementing the From for all lifetimes of a slice seems tricky, maybe its possible, but it doesn’t seem to be a default impl in std::convert. Here is one way that it works for slice. Though it may not be exactly what you want, its a way that works given my above qualifying statements :slight_smile:


pub trait From<T> {
    fn from(T) -> Self;
}

pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}


impl<'a> From<&'a [u8]> for &'a [u8] {
    #[inline]
    fn from(input: &'a [u8]) -> &'a [u8] {
        input
    }
}

impl<'a> AsRef<[u8]> for &'a [u8] {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self
    }
}

pub trait Key<'a> : From<&'a [u8]> + AsRef<[u8]> { }

impl<'a> Key<'a> for &'a [u8] { }

playpen: http://is.gd/IpnioJ


#9

You can involve std::convert as a shortcut to impl From for your type of interest, but for &[u8] it shouldn’t be necessary.