1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! DNS OpCodes

use std::cmp;
use std::convert;
use std::fmt;
use std::hash;


/// DNS OpCodes.
///
/// The opcode specifies the kind of query to be performed.
///
/// The opcode is initially defined in RFC 1035. All currently assigned
/// values can be found at
/// http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5
#[derive(Clone, Copy, Debug)]
pub enum Opcode {
    /// A standard query.
    ///
    /// This query requests all records matching the name, class, and record
    /// type given in the query’s question section.
    ///
    /// This value is defined in RFC 1035.
    Query,

    /// An inverse query (IQUERY) (obsolete).
    ///
    /// The idea behind inverse queries was to provide a single answer and
    /// ask the DNS for all the questions that would lead to this answer.
    /// This kind of query has always been optional, was never widely
    /// supported, and has therefore been declared obsolete.
    ///
    /// This value was defined in RFC 1035 and obsoleted by RFC 3425.
    IQuery,

    /// A server status request.
    ///
    /// This value is defined in RFC 1035. The status request itself was
    /// defined as experimental and ‘to be defined’ in RFC 1034 and seems
    /// to never have been mentioned ever again.
    Status,

    /// A NOTIFY query.
    ///
    /// NOTIFY queries allow master servers to inform slave servers when a
    /// zone has changed.
    ///
    /// This value and the NOTIFY query are defined in RFC 1996.
    Notify,

    /// An UPDATE query.
    ///
    /// The UPDATE query can be used to alter zone content managed by a
    /// master server.
    ///
    /// This value and the UPDATE query are defined in RFC 2136.
    Update,

    /// A raw integer opcode value.
    ///
    /// When converting to an `u8`, only the lower four bits are used.
    Int(u8)
}

impl Opcode {
    /// Creates an Opcode value from an integer value.
    ///
    /// Only considers the lower four bits of `value`.
    pub fn from_int(value: u8) -> Opcode {
        use self::Opcode::*;

        match value & 0x0F {
            0 => Query,
            1 => IQuery,
            2 => Status,
            4 => Notify,
            5 => Update,
            value => Int(value)
        }
    }

    /// Returns the integer value for this opcode.
    pub fn to_int(self) -> u8 {
        use self::Opcode::*;

        match self {
            Query => 0,
            IQuery => 1,
            Status => 2,
            Notify => 4,
            Update => 5,
            Int(value) => value & 0x0F
        }
    }
}


//--- From

impl convert::From<u8> for Opcode {
    fn from(value: u8) -> Opcode { Opcode::from_int(value) }
}

impl convert::From<Opcode> for u8 {
    fn from(value: Opcode) -> u8 { Opcode::to_int(value) }
}


//--- Display

impl fmt::Display for Opcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Opcode::*;

        match *self {
            Query => "QUERY".fmt(f),
            IQuery => "IQUERY".fmt(f),
            Status => "STATUS".fmt(f),
            Notify => "NOTIFY".fmt(f),
            Update => "UPDATE".fmt(f),
            Int(value) => {
                match Opcode::from_int(value) {
                    Int(value) => value.fmt(f),
                    value => value.fmt(f)
                }
            }
        }
    }
}


//--- PartialEq and Eq

impl cmp::PartialEq for Opcode {
    fn eq(&self, other: &Opcode) -> bool {
        self.to_int() == other.to_int()
    }
}

impl cmp::PartialEq<u8> for Opcode {
    fn eq(&self, other: &u8) -> bool {
        self.to_int() == *other
    }
}

impl cmp::PartialEq<Opcode> for u8 {
    fn eq(&self, other: &Opcode) -> bool {
        *self == other.to_int()
    }
}

impl cmp::Eq for Opcode { }


//--- PartialCmp and Cmp

impl cmp::PartialOrd for Opcode {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.to_int().partial_cmp(&other.to_int())
    }
}

impl cmp::PartialOrd<u8> for Opcode {
    fn partial_cmp(&self, other: &u8) -> Option<cmp::Ordering> {
        self.to_int().partial_cmp(other)
    }
}

impl cmp::PartialOrd<Opcode> for u8 {
    fn partial_cmp(&self, other: &Opcode) -> Option<cmp::Ordering> {
        self.partial_cmp(&other.to_int())
    }
}

impl cmp::Ord for Opcode {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.to_int().cmp(&other.to_int())
    }
}


//--- Hash

impl hash::Hash for Opcode {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.to_int().hash(state)
    }
}