2016-11-21 2 views
2

Ich versuche, einen IP-Adresstyp zu implementieren, die im Grunde Wraps u32 implementieren:Wie std :: ops :: Index, wenn der Ausgabewert ist nicht Teil des Typs

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 
pub struct Address(u32); 

Ich bin die Umsetzung der std::ops Operatoren, die für eine IP-Adresse sinnvoll sind (&, |, +, -, usw.). Der einzige, der Probleme verursacht ist std::ops::Index:

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 
pub struct Address(u32); 

enum Byte { 
    A, 
    B, 
    C, 
    D 
} 

impl ops::Index<Byte> for Address { 
    type Output = u8; 

    fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output { 
     match byte { 
      Byte::A => ((self.0 & 0xFF000000) >> 24) as u8, 
      Byte::B => ((self.0 & 0x00FF0000) >> 16) as u8, 
      Byte::C => ((self.0 & 0x0000FF00) >> 8) as u8, 
      Byte::D => (self.0 & 0x000000FF) as u8, 
     } 
    } 
} 

Das ist offensichtlich nicht kompilieren, weil ich kann keine u8 zurück, wenn &u8 erwartet wird. Der naive Versuch, es zu beheben wäre:

impl ops::Index<Byte> for Address { 
    type Output = u8; 

    fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output { 
     match byte { 
      Byte::A => &(((self.0 & 0xFF000000) >> 24) as u8), 
      Byte::B => &(((self.0 & 0x00FF0000) >> 16) as u8), 
      Byte::C => &(((self.0 & 0x0000FF00) >> 8) as u8), 
      Byte::D => &((self.0 & 0x000000FF) as u8), 
     } 
    } 
} 

Aber natürlich kann ich nicht einen Verweis auf einen Wert zurückgeben, der nicht mehr, wenn die Funktion zurückkehrt vorhanden ist.

ich dort eine Möglichkeit zu implementieren std::ops::Index in diesem Fall? Es scheint mir nicht so, aber ich hoffe, dass jemand mir das Gegenteil beweisen kann.

+1

Auf die Gefahr hin, etwas offensichtlich zu verpassen, gibt es bereits eine ['Ipv4Addr'] (https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html), die den entsprechenden zugrunde liegenden Typ umschließt. – Shepmaster

+0

@Shempmaster, ja, aber ich möchte dies in einem Verkehrserzeugungstool verwenden, also möchte ich (mindestens) die '+', '&', '<<' and '>>' Operatoren implementiert. Afaik kann ich nicht einfach auf 'Ipv4Addr' implementieren, da ich keinen direkten Zugriff auf den zugrunde liegenden Typ habe. –

Antwort

6

Nun, die einfachste und idiomatische Weg, dies zu lösen, ist zu nichtIndex implementieren und stattdessen nur eine Methode octet oder etwas namens verwenden. Index dient zum Indexieren in Containern; Es ist einfach nicht kompatibel mit der Generierung neuer Werte im laufenden Betrieb.

So. Da ist deine Antwort.


Sie sollten unbedingt nicht tun alles, was ich über zu beschreiben bin, denn es gibt keinen guten Grund, es zu tun, und ich schreibe es nur, weil Sie technisch gefragt, ob es war auf jeden Fall ...

Sie wurden gewarnt.

... Die Oktette sind genau dort! Es sei denn, Sie sind für eine Maschine mit Bytes kompilieren, die sind nicht 8 Bits, oder hat mehr granulare Adressierung als 8 Bit, gibt es keinen Grund kann man nicht einfach dies tun:

use std::ops; 

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 
pub struct Address(u32); 

enum Byte { 
    A, 
    B, 
    C, 
    D 
} 

impl ops::Index<Byte> for Address { 
    type Output = u8; 

    #[cfg(target_endian="big")] 
    fn index<'a>(&'a self, byte: Byte) -> &'a u8 { 
     use std::mem; 
     let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) }; 
     match byte { 
      Byte::A => &bytes[0], 
      Byte::B => &bytes[1], 
      Byte::C => &bytes[2], 
      Byte::D => &bytes[3], 
     } 
    } 

    #[cfg(target_endian="little")] 
    fn index<'a>(&'a self, byte: Byte) -> &'a u8 { 
     use std::mem; 
     let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) }; 
     match byte { 
      Byte::A => &bytes[3], 
      Byte::B => &bytes[2], 
      Byte::C => &bytes[1], 
      Byte::D => &bytes[0], 
     } 
    } 
} 

fn main() { 
    assert_eq!(Address(0x12345678)[Byte::A], 0x12); 
} 

Ich meine, abgesehen daraus ergibt sich eine unnötige Verwendung von unsafe wegen der verwirrenden Syntax; Indizierung eine Adresse macht etwa so viel Sinn wie Indexierung einer ganzen Zahl: sehr wenig.

+0

Vielen Dank für die Erklärung _why_ es ist eine falsche Sache zu tun, und die Frage trotzdem zu beantworten. Ich implementiere 'Index' nicht, das verspreche ich! –

Verwandte Themen