#How to restrict a generic type with traits.

11 messages · Page 1 of 1 (latest)

next heron
#

I'm trying to implement different data types. I thought I'm very smart with using a struct which contains information about the data type and the content. I hope that the option type doesn't interfere with my size, as this would render the use of a union useless. Anyway I'm having problems retrieving the data.

pub struct Value {
    data_type: DataType,
    data: Option<Data>,
}

pub enum DataType {
    Bool,
    Number,
    Nil,
}

#[repr(C)]
pub union Data {
    boolean: bool,
    number: f64,
}

pub trait IsData{}

impl IsData for bool{}
impl IsData for f64{}


pub trait InputConverter<T> {
    fn convert_input(data: T) -> Data;
}

impl InputConverter<bool> for bool {
    fn convert_input(data: bool) -> Data {
        Data { boolean: data }
    }
}

impl InputConverter<f64> for f64 {
    fn convert_input(data: f64) -> Data {
        Data { number: data }
    }
}

impl Value {
    pub fn new<T>(data_type: DataType, data: T) -> Self
    where
        T: InputConverter<T>,
        T: IsData
    {
        let data: Option<Data> = match data_type {
            DataType::Bool => Some(T::convert_input(data)),
            DataType::Number => Some(T::convert_input(data)),
            DataType::Nil => None,
        };
        Self {data_type, data}
    }

    pub fn get_data<T: IsData>(value: &Value) -> Option<&T>{
        match value.data_type{
            DataType::Bool => unsafe{Some(&value.data.unwrap().boolean)},
            DataType::Number => unsafe{Some(&value.data.unwrap().boolean)},
            DataType::Nil => None
        }
    }
}
#

This is the error I'm unable to resolve ```rs
error[E0308]: mismatched types
--> src/backend/common.rs:56:43
|
54 | pub fn get_data<T: IsData>(value: &Value) -> Option<&T>{
| - expected this type parameter
55 | match value.data_type{
56 | DataType::Bool => unsafe{Some(&value.data.unwrap().boolean)},
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &T, found &bool
| |
| arguments to this enum variant are incorrect
|
= note: expected reference &T
found reference &bool
help: the type constructed contains &bool due to the type of the argument passed
--> src/backend/common.rs:56:38
|
56 | DataType::Bool => unsafe{Some(&value.data.unwrap().boolean)},
| ^^^^^----------------------------^
| |
| this argument influences the type of Some
note: tuple variant defined here
--> /Users/juliuskorbjuhn/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:577:5
|
577 | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
| ^^^^

indigo drift
#

are you just reimplementing tagged unions here?

next heron
#

Pretty much, if you know a better way to achieve the same thing, let me know

indigo drift
#

Rust literally has tagged unions built in to the language with its enums

next heron
#

Yes but I want to do it myself

indigo drift
#

why?

next heron
#

Like yes I could've used a vec for my byte code storage but I didn't. I don't know if this is stupid but I want to learn rust by implementing all the small details. Essentially combating my skill issue

indigo drift
#

if this is stupid
kind of

anyway, the problem here is that rs pub fn get_data<T: IsData>(value: &Value) -> Option<&T>{ match value.data_type{ DataType::Bool => unsafe{Some(&value.data.unwrap().boolean)}, DataType::Number => unsafe{Some(&value.data.unwrap().boolean)}, DataType::Nil => None } } the function is specified to return T, so it has to return that generic parameter

a better way to do this (if you insist on reinventing the wheel yourself) would probably be through a generic trait, similar to AsRef<T>, but one that returns an Option<&T> instead

next heron
#

Thank you! I really appreciate the help!

livid vigil
#

Just to address Option and size real quick, most of the time it will affect the size. In some cases rust can use a niche optimization where it can fit the tag into the type's bit representation (for example with Option<bool> it only needs two separate bits to represent Some(bool)/None and true/false which will fit into one byte)