2016-05-17 9 views
1

Ich versuche C++ - Code nach Rust zu portieren. Es erstellt eine virtuelle (.mp4) Datei aus einigen Arten von Slices (String-Referenz, lazy-evaluated String-Referenz, Teil einer physischen Datei) und bedient HTTP-Anfragen basierend auf dem Ergebnis. (Wenn Sie neugierig sind, sehen Mp4File, die die Vorteile der FileSlice-Schnittstelle und die konkreten Implementierungen in http.h nimmt.)Vec <MyTrait> ohne N Heap-Zuordnungen?

Hier ist das Problem: Ich benötige will so wenig Heapzuweisungen wie möglich. Lassen Sie uns sagen, ich habe ein paar Implementierungen von resource::Slice, die ich hoffentlich selbst herausfinden kann. Dann möchte ich das machen, dass sie alle komponiert:

pub trait Slice : Send + Sync { 
    /// Returns the length of the slice in bytes. 
    fn len(&self) -> u64; 

    /// Writes bytes indicated by `range` to `out.` 
    fn write_to(&self, range: &ByteRange, 
       out: &mut io::Write) -> io::Result<()>; 
} 

// (used below) 
struct SliceInfo<'a> { 
    range: ByteRange, 
    slice: &'a Slice, 
} 

/// A `Slice` composed of other `Slice`s.  
pub struct Slices<'a> { 
    len: u64, 
    slices: Vec<SliceInfo<'a>>, 
} 

impl<'a> Slices<'a> { 
    pub fn new() -> Slices<'a> { ... } 
    pub fn append(&mut self, slice: &'a resource::Slice) { ... } 
} 

impl<'a> Slice for Slices<'a> { ... } 

und nutzen sie anhängen viele, viele Scheiben mit möglichst wenigen Heapzuweisungen wie möglich. Vereinfacht, etwas in der Art:

struct ThingUsedWithinMp4Resource { 
    slice_a: resource::LazySlice, 
    slice_b: resource::LazySlice, 
    slice_c: resource::LazySlice, 
    slice_d: resource::FileSlice, 
} 

struct Mp4Resource { 
    slice_a: resource::StringSlice, 
    slice_b: resource::LazySlice, 
    slice_c: resource::StringSlice, 
    slice_d: resource::LazySlice, 
    things: Vec<ThingUsedWithinMp4Resource>, 
    slices: resource::Slices 
} 

impl Mp4Resource { 
    fn new() { 
     let mut f = Mp4Resource{slice_a: ..., 
           slice_b: ..., 
           slice_c: ..., 
           slices: resource::Slices::new()}; 
     // ...fill `things` with hundreds of things... 
     slices.append(&f.slice_a); 
     for thing in f.things { slices.append(&thing.slice_a); } 
     slices.append(&f.slice_b); 
     for thing in f.things { slices.append(&thing.slice_b); } 
     slices.append(&f.slice_c); 
     for thing in f.things { slices.append(&thing.slice_c); } 
     slices.append(&f.slice_d); 
     for thing in f.things { slices.append(&thing.slice_d); } 
     f; 
    } 
} 

aber das funktioniert nicht. Die append-Zeilen verursachen Fehler "f.slice_ * lebt nicht lange genug", "Referenz muss für die Lebenszeit gültig sein" a wie im Block unter ... definiert "," ... aber der geborgte Wert gilt nur für die Block Suffix folgende Anweisung ". Ich denke, das ist ähnlich wie this question über die selbstreferenzierende Struktur. Das ist im Grunde das, mit mehr Indirektheit. Und anscheinend ist es unmöglich.

Was kann ich stattdessen tun?

ich glaube, ich würde glücklich sein Eigentum der resource::Slices in append zu geben, aber ich kann keine resource::Slice im SliceInfo in Vec<SliceInfo> verwendet setzen, weil resource::Slice ein Merkmal ist, und Züge sind unsized. Ich könnte stattdessen eine Box<resource::Slice> tun, aber das bedeutet eine separate Heap-Zuweisung für jede Scheibe. Ich möchte das vermeiden. (Es kann Tausende von Scheiben pro Mp4Resource sein.)

Ich denke, eine ENUM zu tun, so etwas wie:

enum BasicSlice { 
    String(StringSlice), 
    Lazy(LazySlice), 
    File(FileSlice) 
}; 

und die Verwendung dieser in den SliceInfo. Ich denke, ich kann das schaffen. Aber es begrenzt definitiv den Nutzen meiner Klasse resource::Slices. Ich möchte erlauben, dass es leicht in Situationen verwendet wird, die ich nicht vorausgesehen habe, vorzugsweise ohne jedes Mal ein neues Enum definieren zu müssen.

Weitere Optionen?

+2

Wenn ein Element mit begrenzter Lebensdauer in der Struktur enthalten ist, hat die Struktur auch eine begrenzte Lebensdauer. – WiSaGaN

+0

@WiSaGaN Was hat gesagt, dass ein limited lifetime item im struct enthalten ist? Mein erster Ansatz bestand darin, ein Element einzubeziehen, das genau so lange lebt, wie es die Struktur sonst tun würde. Aber ich denke, es gibt keine Möglichkeit, dieses Leben auszudrücken, daher ist die selbstreferenzierende Struktur unmöglich. Wie auch immer, ich bin glücklich, einen anderen Weg zu finden, wie ich in der Frage gesagt habe ... –

+0

Nun, außer das stimmt nicht genau. Zumindest in C++ ausgedrückt, werden die Mitglieder einer Klasse so konstruiert, dass sie in umgekehrter Reihenfolge zerstört werden, und ich hatte ein späteres Mitglied, das auf ein früheres Mitglied verweist. Das ist eine sichere Sache, und ich würde sie gerne in zwei separaten Heap-Zuweisungen machen, wenn das helfen würde. Aber es scheint, als ob die Lebenszeit immer noch durchlaufen werden muss ... –

Antwort

4

Sie können eine User Variante zu Ihrer BasicSlice enum hinzufügen, die eine Box<SliceInfo> dauert. Auf diese Weise wird nur der spezialisierte Fall von Benutzern die zusätzliche Zuweisung übernehmen, während der normale Pfad optimiert wird.

Verwandte Themen