rust - Do I need any of the *variantType markers? -
i'm trying interact type-unsafe c library in type-safe way rust. c interface deals void
pointers. specifically, there write
, read
function takes such void
pointer parameter , obvious things (write given data place else or read place given buffer). kind of data is, agreed upon earlier py bassing integer value open
function
1 = float 2 = int32_t 4 = int16_t etc...
i represent opened output stream (where user can call write on) parameterized rust struct one:
pub struct outputstream<t> { c_stream: *mut () } impl<t: valuetype> outputstream<t> { pub fn write(&mut self, data: &[t]) -> result<(),someerrortype> { unsafe { ... } } }
where valuetype
trait wrote supported value types in way nobody else can implement (private base trait trick). so, t not mentioned anywhere within struct. seems case contravarianttype marker. don't understand these type markers. visiting wikipedia page on variance not help. don't see connection between variance , how applies rust's type parameters. , don't know kind of marker prevent.
so questions are: need 1 of these markers outputstream
? if so, 1 , why? prevent using it? same goes inputstream
provides read
method instead of write
method.
in general, variance determines subtyping relationship between parameterized types regard parameters:
covariance: t <: u => f[t] <: f[u] contravariance: t <: u => f[u] <: f[t] invariance: t <: u => neither of above bivariance: t <: u => both of above
your type is naturally contravariant: methods consume values of type t
, not produce them; so-called consumer type. however, subtyping in rust limited; far know, types allow subtyping relationship of kind references (for example, can pass &'static str
&'a str
variable because 'static
lifetime greater or equal other lifetime, &'static str
subtype of &'a str
'a
).
so, if understand correctly, need variance annotation. if t
parameter can reference, use contravarianttype
, this:
fn push_something_to(os: outputstream<&'static str>) { ... } let s: outputstream<&'a str> = ...; // , 'a less 'static push_something_to(s); // safe because &'static str valid &'a str
but couldn't this:
let s: outputstream<int> = ...; push_something_to(s); // oops, push_something_to expects stream of &'static str
with invarianttype
both forbidden.
however, there seems deep misunderstanding on side, because neither code in documentation on variance markers, nor own code not work in current rust me:
use std::ptr; use std::mem; struct s<t> { x: *const () } fn get<t>(s: &s<t>, v: t) { unsafe { let x: fn(t) = mem::transmute(s.x); x(v) } } fn main() { let s: s<int> = s { x: ptr::null() }; get::<box<int>>(&s, box 1); }
according documentation, should compile due parameterized types being bivariant default, doesn't: acts if parameter invariant.
and own example:
#![allow(dead_code)] type f<t> = fn(t); fn test_1<'a>(f: f<&'a str>) -> f<&'static str> { f } struct s<t> { _m: std::kinds::marker::contravarianttype<t> } fn test_2<'a>(s: s<&'a str>) -> s<&'static str> { s } fn main() {}
as far understand, program should compile, doesn't:
<anon>:9:5: 9:6 error: mismatched types: expected `s<&'static str>` found `s<&'a str>` (lifetime mismatch) <anon>:9 s ^ <anon>:8:47: 10:2 note: lifetime 'a defined on block @ 8:46... <anon>:8 fn test<'a>(s: s<&'a str>) -> s<&'static str> { <anon>:9 s <anon>:10 } note: ...does not outlive static lifetime
if remove s
, test_2
, compiles fine, demonstrating function types indeed contravariant regard argument types.
i don't know what's happening , looks deserves question.
Comments
Post a Comment