[rust] Add eui48 0.4.1

OSRB-130 #done

Change-Id: Ia76c6a404d22d0570b4b1212b53f31fcdc6bfd5c
diff --git a/rustc_deps/Cargo.lock b/rustc_deps/Cargo.lock
index 05c753d..2b31921 100644
--- a/rustc_deps/Cargo.lock
+++ b/rustc_deps/Cargo.lock
@@ -396,6 +396,15 @@
 ]
 
 [[package]]
+name = "eui48"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "failure"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -480,6 +489,7 @@
  "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "derp 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "eui48 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-rs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fuchsia-async-macro 0.1.0",
@@ -2149,6 +2159,7 @@
 "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 "checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727"
+"checksum eui48 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "649dadb113dc16aadb072edac675ce773a81d9aad09750b40146b7ac14a5118e"
 "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
 "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
 "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
diff --git a/rustc_deps/Cargo.toml b/rustc_deps/Cargo.toml
index b1be74e..5b96f9a 100644
--- a/rustc_deps/Cargo.toml
+++ b/rustc_deps/Cargo.toml
@@ -22,6 +22,7 @@
 data-encoding = "2.1.2"
 derp = "0.0.11"
 euclid = "0.19"
+eui48 = { version = "0.4.1", features = ["serde"] }
 failure = "0.1.1"
 font-rs = "0.1.3"
 fuchsia-async-macro = "0.1"
diff --git a/rustc_deps/vendor/eui48/.cargo-checksum.json b/rustc_deps/vendor/eui48/.cargo-checksum.json
new file mode 100644
index 0000000..75387da
--- /dev/null
+++ b/rustc_deps/vendor/eui48/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"1b18d7c20632e974f830352d0d976d6756a8496d5b719670101653431e564f61","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1b0b883046733d2c0b66fccbde45ee92c650598d8c25ef061b3f0d9e7853fa22","src/lib.rs":"fadd186f0c47882bf153a665eb6fca7eb58b5bfe970044051cf89da1501eb331"},"package":"649dadb113dc16aadb072edac675ce773a81d9aad09750b40146b7ac14a5118e"}
\ No newline at end of file
diff --git a/rustc_deps/vendor/eui48/Cargo.toml b/rustc_deps/vendor/eui48/Cargo.toml
new file mode 100644
index 0000000..315ca1c
--- /dev/null
+++ b/rustc_deps/vendor/eui48/Cargo.toml
@@ -0,0 +1,29 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "eui48"
+version = "0.4.1"
+authors = ["Andrew Baumhauer <andy@baumhauer.us>", "<rlcomstock3@github.com>", "Michal 'vorner' Vaner <vorner+github@vorner.cz>"]
+description = "A library to generate and parse IEEE EUI-48 and EUI-64, also known as MAC-48 media access\ncontrol addresses. The IEEE claims trademarks on the names EUI-48 and EUI-64, in which EUI is an\nabbreviation for Extended Unique Identifier.\n"
+homepage = "https://github.com/abaumhauer/eui48"
+documentation = "https://docs.rs/eui48/0.3.1/eui48/"
+readme = "README.md"
+keywords = ["EUI-48", "MAC", "MAC-48", "networking", "MACADDR"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/abaumhauer/eui48"
+[dependencies.rustc-serialize]
+version = "0.3.24"
+
+[dependencies.serde]
+version = "1.0.80"
+optional = true
diff --git a/rustc_deps/vendor/eui48/LICENSE-APACHE b/rustc_deps/vendor/eui48/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/rustc_deps/vendor/eui48/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rustc_deps/vendor/eui48/LICENSE-MIT b/rustc_deps/vendor/eui48/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/rustc_deps/vendor/eui48/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rustc_deps/vendor/eui48/README.md b/rustc_deps/vendor/eui48/README.md
new file mode 100644
index 0000000..1279dd1
--- /dev/null
+++ b/rustc_deps/vendor/eui48/README.md
@@ -0,0 +1,64 @@
+eui48
+====
+
+[![Build Status](https://travis-ci.org/abaumhauer/eui48.svg?branch=master)](https://travis-ci.org/abaumhauer/eui48)
+[![Documentation](https://docs.rs/abaumhauer/badge.svg)](https://docs.rs/eui48/)
+[![Crate](https://img.shields.io/crates/v/eui48.svg)](https://crates.io/crates/eui48)
+
+A Rust library to represent and parse IEEE EUI-48 also known as MAC-48 media access control addresses. The IEEE claims trademarks on the names EUI-48 and EUI-64, in which EUI is an abbreviation for Extended Unique Identifier.
+
+
+[Documentation](https://docs.rs/eui48)
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+
+eui48 = "0.4.0"
+```
+
+and this to your crate root:
+
+```rust
+extern crate eui48;
+```
+
+## Examples
+
+To create a new MAC address and print it out in canonical form:
+
+```rust
+extern crate eui48;
+use eui48::{MacAddress, Eui48};
+
+fn main() {
+	let eui: Eui48 = [ 0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF ];
+	let mac = MacAddress::new( eui );
+
+	println!("{}", mac.to_canonical());
+	println!("{}", mac.to_hex_string());
+	println!("{}", mac.to_dot_string());
+	println!("{}", mac.to_hexadecimal());
+	println!("{}", mac.to_interfaceid());
+	println!("{}", mac.to_link_local());
+
+	let mac = MacAddress::parse_str( "01-02-03-0A-0b-0f" ).expect("Parse error {}");
+	let mac = MacAddress::parse_str( "01:02:03:0A:0b:0f" ).expect("Parse error {}");
+	let mac = MacAddress::parse_str( "0102.030A.0b0f" ).expect("Parse error {}");
+	let mac = MacAddress::parse_str( "0x1234567890ab" ).expect("Parse error {}");
+}
+```
+
+## References
+[Wikipedia: MAC address](https://en.wikipedia.org/wiki/MAC_address)
+
+## Authors
+- 0.1 Andrew Baumhauer - Initial design
+- 0.2 rlcomstock3 - Added support for btree keys
+- 0.3 Michal 'vorner' Vaner <vorner+github@vorner.cz> - Serde 1.0 support
+- 0.3.1 Michal 'vorner' Vaner <vorner+github@vorner.cz> - Derive useful traits
+- 0.4.0 Rainer Stademann - Define ABI as repr(C)
+- 0.4.1 Andrew Baumhauer - Add IPv6 Interface ID and Link Local conversions
diff --git a/rustc_deps/vendor/eui48/src/lib.rs b/rustc_deps/vendor/eui48/src/lib.rs
new file mode 100644
index 0000000..f5d4df5
--- /dev/null
+++ b/rustc_deps/vendor/eui48/src/lib.rs
@@ -0,0 +1,642 @@
+// Copyright 2016 Andrew Baumhauer <andy@baumhauer.us>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Represent and parse IEEE EUI-48 Media Access Control addresses
+//! The IEEE claims trademarks on the names EUI-48 and EUI-64, in which EUI is an
+//! abbreviation for Extended Unique Identifier.
+
+#![doc(
+    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+    html_root_url = "https://doc.rust-lang.org/eui48/"
+)]
+#![cfg_attr(test, deny(warnings))]
+
+extern crate rustc_serialize;
+#[cfg(feature = "serde")]
+extern crate serde;
+
+use std::default::Default;
+use std::error::Error;
+use std::fmt;
+use std::str::FromStr;
+
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+#[cfg(feature = "serde")]
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+/// A 48-bit (6 byte) buffer containing the EUI address
+pub const EUI48LEN: usize = 6;
+pub type Eui48 = [u8; EUI48LEN];
+
+/// A 64-bit (8 byte) buffer containing the EUI address
+pub const EUI64LEN: usize = 8;
+pub type Eui64 = [u8; EUI64LEN];
+
+/// A MAC address (EUI-48)
+#[repr(C)]
+#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
+pub struct MacAddress {
+    /// The 48-bit number stored in 6 bytes
+    eui: Eui48,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+/// Format to display MacAddress
+pub enum MacAddressFormat {
+    /// Use - notaion
+    Canonical,
+    /// Use : notation
+    HexString,
+    /// Use . notation
+    DotNotation,
+    /// Use 0x notation
+    Hexadecimal,
+}
+
+#[derive(PartialEq, Eq, Copy, Clone, Debug, Ord, PartialOrd, Hash)]
+/// Parsing errors
+pub enum ParseError {
+    /// Length is incorrect (should be 14 or 17)
+    InvalidLength(usize),
+    /// Character not [0-9a-fA-F]|'x'|'-'|':'|'.'
+    InvalidCharacter(char, usize),
+}
+
+impl MacAddress {
+    /// Create a new MacAddress from `[u8; 6]`.
+    pub fn new(eui: Eui48) -> MacAddress {
+        MacAddress { eui: eui }
+    }
+
+    /// Create a new MacAddress from a byte slice.
+    ///
+    /// Returns an error (without any description) if the slice doesn't have the proper length.
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ()> {
+        if bytes.len() != EUI48LEN {
+            return Err(());
+        }
+        let mut input: [u8; EUI48LEN] = Default::default();
+        for i in 0..EUI48LEN {
+            input[i] = bytes[i];
+        }
+        Ok(Self::new(input))
+    }
+
+    /// Returns empty EUI-48 address
+    pub fn nil() -> MacAddress {
+        MacAddress { eui: [0; EUI48LEN] }
+    }
+
+    /// Returns 'ff:ff:ff:ff:ff:ff', a MAC broadcast address
+    pub fn broadcast() -> MacAddress {
+        MacAddress {
+            eui: [0xFF; EUI48LEN],
+        }
+    }
+
+    /// Returns true if the address is '00:00:00:00:00:00'
+    pub fn is_nil(&self) -> bool {
+        self.eui.iter().all(|&b| b == 0)
+    }
+
+    /// Returns true if the address is 'ff:ff:ff:ff:ff:ff'
+    pub fn is_broadcast(&self) -> bool {
+        self.eui.iter().all(|&b| b == 0xFF)
+    }
+
+    /// Returns true if bit 1 of Y is 1 in address 'xY:xx:xx:xx:xx:xx'
+    pub fn is_unicast(&self) -> bool {
+        self.eui[0] & 0 == 0
+    }
+
+    /// Returns true if bit 1 of Y is 1 in address 'xY:xx:xx:xx:xx:xx'
+    pub fn is_multicast(&self) -> bool {
+        self.eui[0] & 1 != 0
+    }
+
+    /// Returns true if bit 2 of Y is 0 in address 'xY:xx:xx:xx:xx:xx'
+    pub fn is_universal(&self) -> bool {
+        self.eui[0] & 1 << 1 == 0
+    }
+
+    /// Returns true if bit 2 of Y is 1 in address 'xY:xx:xx:xx:xx:xx'
+    pub fn is_local(&self) -> bool {
+        self.eui[0] & 1 << 1 != 0
+    }
+
+    /// Returns a String representation in the format '00-00-00-00-00-00'
+    pub fn to_canonical(&self) -> String {
+        format!(
+            "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
+            self.eui[0], self.eui[1], self.eui[2], self.eui[3], self.eui[4], self.eui[5]
+        )
+    }
+
+    /// Returns a String representation in the format '00:00:00:00:00:00'
+    pub fn to_hex_string(&self) -> String {
+        format!(
+            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+            self.eui[0], self.eui[1], self.eui[2], self.eui[3], self.eui[4], self.eui[5]
+        )
+    }
+
+    /// Returns a String representation in the format '0000.0000.0000'
+    pub fn to_dot_string(&self) -> String {
+        format!(
+            "{:02x}{:02x}.{:02x}{:02x}.{:02x}{:02x}",
+            self.eui[0], self.eui[1], self.eui[2], self.eui[3], self.eui[4], self.eui[5]
+        )
+    }
+
+    /// Returns a String representation in the format '0x000000000000'
+    pub fn to_hexadecimal(&self) -> String {
+        format!(
+            "0x{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
+            self.eui[0], self.eui[1], self.eui[2], self.eui[3], self.eui[4], self.eui[5]
+        )
+    }
+
+    /// Returns a String representation in the EUI-64 interface ID format '0000:00ff:fe00:0000'
+    pub fn to_interfaceid(&self) -> String {
+        format!(
+            "{:02x}{:02x}:{:02x}ff:fe{:02x}:{:02x}{:02x}",
+            (self.eui[0] ^ 0x02),
+            self.eui[1],
+            self.eui[2],
+            self.eui[3],
+            self.eui[4],
+            self.eui[5]
+        )
+    }
+
+    /// Returns a String representation in the IPv6 link local format 'ff80::0000:00ff:fe00:0000'
+    pub fn to_link_local(&self) -> String {
+        format!(
+            "ff80::{:02x}{:02x}:{:02x}ff:fe{:02x}:{:02x}{:02x}",
+            (self.eui[0] ^ 0x02),
+            self.eui[1],
+            self.eui[2],
+            self.eui[3],
+            self.eui[4],
+            self.eui[5]
+        )
+    }
+
+    /// Returns a String in the format selected by fmt
+    pub fn to_string(&self, fmt: MacAddressFormat) -> String {
+        match fmt {
+            MacAddressFormat::Canonical => self.to_canonical(),
+            MacAddressFormat::HexString => self.to_hex_string(),
+            MacAddressFormat::DotNotation => self.to_dot_string(),
+            MacAddressFormat::Hexadecimal => self.to_hexadecimal(),
+        }
+    }
+
+    /// Parses a String representation from any format supported
+    pub fn parse_str(s: &str) -> Result<MacAddress, ParseError> {
+        let mut offset = 0; // Offset into the u8 Eui48 vector
+        let mut hn: bool = false; // Have we seen the high nibble yet?
+        let mut eui: Eui48 = [0; EUI48LEN];
+
+        match s.len() {
+            14 | 17 => {} // The formats are all 12 characters with 2 or 5 delims
+            _ => return Err(ParseError::InvalidLength(s.len())),
+        }
+
+        for (idx, c) in s.chars().enumerate() {
+            if offset >= EUI48LEN {
+                // We shouln't still be parsing
+                return Err(ParseError::InvalidLength(s.len()));
+            }
+
+            match c {
+                '0'...'9' | 'a'...'f' | 'A'...'F' => {
+                    match hn {
+                        false => {
+                            // We will match '0' and run this even if the format is 0x
+                            hn = true; // Parsed the high nibble
+                            eui[offset] = (c.to_digit(16).unwrap() as u8) << 4;
+                        }
+                        true => {
+                            hn = false; // Parsed the low nibble
+                            eui[offset] += c.to_digit(16).unwrap() as u8;
+                            offset += 1;
+                        }
+                    }
+                }
+                '-' | ':' | '.' => {}
+                'x' | 'X' => {
+                    match idx {
+                        1 => {
+                            // If idx = 1, we are possibly parsing 0x1234567890ab format
+                            // Reset the offset to zero to ignore the first two characters
+                            offset = 0;
+                            hn = false;
+                        }
+                        _ => return Err(ParseError::InvalidCharacter(c, idx)),
+                    }
+                }
+                _ => return Err(ParseError::InvalidCharacter(c, idx)),
+            }
+        }
+
+        if offset == EUI48LEN {
+            // A correctly parsed value is exactly 6 u8s
+            Ok(MacAddress::new(eui))
+        } else {
+            Err(ParseError::InvalidLength(s.len())) // Something slipped through
+        }
+    }
+
+    /// Return the internal structure as a slice of bytes
+    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+        &self.eui
+    }
+}
+
+impl FromStr for MacAddress {
+    type Err = ParseError;
+    /// Create a MacAddress from String
+    fn from_str(us: &str) -> Result<MacAddress, ParseError> {
+        MacAddress::parse_str(us)
+    }
+}
+
+impl Default for MacAddress {
+    /// Create a Default MacAddress (00-00-00-00-00-00)
+    fn default() -> MacAddress {
+        MacAddress::nil()
+    }
+}
+
+impl fmt::Debug for MacAddress {
+    /// Debug format for MacAddress is HexString notation
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "MacAddress(\"{}\")",
+            self.to_string(MacAddressFormat::HexString)
+        )
+    }
+}
+
+impl fmt::Display for MacAddress {
+    /// Display format is canonical format (00-00-00-00-00-00)
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_string(MacAddressFormat::Canonical))
+    }
+}
+
+impl fmt::Display for ParseError {
+    /// Human readable error strings for ParseError enum
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ParseError::InvalidLength(found) => write!(
+                f,
+                "Invalid length; expecting 14 or 17 chars, found {}",
+                found
+            ),
+            ParseError::InvalidCharacter(found, pos) => {
+                write!(f, "Invalid character; found `{}` at offset {}", found, pos)
+            }
+        }
+    }
+}
+
+impl Error for ParseError {
+    /// Human readable description for ParseError enum
+    fn description(&self) -> &str {
+        "MacAddress parse error"
+    }
+}
+
+impl Encodable for MacAddress {
+    /// Encode a MacAddress as canonical form
+    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+        e.emit_str(&self.to_canonical())
+    }
+}
+
+impl Decodable for MacAddress {
+    /// Decode a MacAddress from a string in canonical form
+    fn decode<D: Decoder>(d: &mut D) -> Result<MacAddress, D::Error> {
+        let string = try!(d.read_str());
+        string.parse().map_err(|err| d.error(&format!("{}", err)))
+    }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for MacAddress {
+    /// Serialize a MacAddress as canonical form using the serde crate
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        serializer.serialize_str(&self.to_canonical())
+    }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for MacAddress {
+    /// Deserialize a MacAddress from canonical form using the serde crate
+    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+        struct MacAddressVisitor;
+        impl<'de> de::Visitor<'de> for MacAddressVisitor {
+            type Value = MacAddress;
+
+            fn visit_str<E: de::Error>(self, value: &str) -> Result<MacAddress, E> {
+                value.parse().map_err(|err| E::custom(&format!("{}", err)))
+            }
+
+            fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<MacAddress, E> {
+                MacAddress::from_bytes(value).map_err(|_| E::invalid_length(value.len(), &self))
+            }
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                write!(
+                    formatter,
+                    "either a string representation of a MAC address or 6-element byte array"
+                )
+            }
+        }
+        deserializer.deserialize_str(MacAddressVisitor)
+    }
+}
+
+// ************** TESTS BEGIN HERE ***************
+#[cfg(test)]
+mod tests {
+    use super::{Eui48, MacAddress, MacAddressFormat};
+
+    #[test]
+    fn test_new() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+
+        assert!(mac.eui[0..5] == eui[0..5]);
+    }
+
+    #[test]
+    fn test_nil() {
+        let nil = MacAddress::nil();
+        let not_nil = MacAddress::broadcast();
+        assert!(nil.is_nil());
+        assert!(!not_nil.is_nil());
+    }
+
+    #[test]
+    fn test_broadcast() {
+        let broadcast = MacAddress::broadcast();
+        let not_broadcast = MacAddress::nil();
+        assert!(broadcast.is_broadcast());
+        assert!(!not_broadcast.is_broadcast());
+    }
+
+    #[test]
+    fn test_is_nil() {
+        let nil = MacAddress::nil();
+        assert!(nil.is_nil());
+    }
+
+    #[test]
+    fn test_is_broadcast() {
+        let broadcast = MacAddress::broadcast();
+        assert!(broadcast.is_broadcast());
+    }
+
+    #[test]
+    fn test_is_unicast() {
+        let mac = MacAddress::parse_str("FE:00:5E:AB:CD:EF").unwrap();
+        assert!(mac.is_unicast());
+        assert!(MacAddress::nil().is_unicast());
+    }
+
+    #[test]
+    fn test_is_multicast() {
+        let mac = MacAddress::parse_str("01:00:5E:AB:CD:EF").unwrap();
+        assert!(mac.is_multicast());
+        assert!(MacAddress::broadcast().is_multicast());
+    }
+
+    #[test]
+    fn test_is_universal() {
+        let mac = MacAddress::parse_str("15:24:56:AB:CD:EF").unwrap();
+        assert!(mac.is_universal());
+    }
+
+    #[test]
+    fn test_is_local() {
+        let mac = MacAddress::parse_str("16:34:56:AB:CD:EF").unwrap();
+        assert!(mac.is_local());
+    }
+
+    #[test]
+    fn test_to_canonical() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        let s = format!("{}", mac);
+        assert_eq!(s, mac.to_canonical());
+        assert_eq!("12-34-56-ab-cd-ef", mac.to_canonical());
+    }
+
+    #[test]
+    fn test_to_hex_string() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!("12:34:56:ab:cd:ef", mac.to_hex_string());
+    }
+
+    #[test]
+    fn test_to_dot_string() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!("1234.56ab.cdef", mac.to_dot_string());
+    }
+
+    #[test]
+    fn test_to_hexadecimal() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!("0x123456abcdef", mac.to_hexadecimal());
+    }
+
+    #[test]
+    fn test_to_interfaceid() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!("1034:56ff:feab:cdef", mac.to_interfaceid());
+    }
+
+    #[test]
+    fn test_to_link_local() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!("ff80::1034:56ff:feab:cdef", mac.to_link_local());
+    }
+
+    #[test]
+    fn test_to_string() {
+        let eui: Eui48 = [0x12, 0x34, 0x56, 0xAB, 0xCD, 0xEF];
+        let mac = MacAddress::new(eui);
+        assert_eq!(
+            "0x123456abcdef",
+            mac.to_string(MacAddressFormat::Hexadecimal)
+        );
+        assert_eq!(
+            "1234.56ab.cdef",
+            mac.to_string(MacAddressFormat::DotNotation)
+        );
+        assert_eq!(
+            "12:34:56:ab:cd:ef",
+            mac.to_string(MacAddressFormat::HexString)
+        );
+        assert_eq!(
+            "12-34-56-ab-cd-ef",
+            mac.to_string(MacAddressFormat::Canonical)
+        );
+    }
+
+    #[test]
+    fn test_parse_str() {
+        use super::ParseError::*;
+
+        assert_eq!(
+            "0x123456abcdef",
+            MacAddress::parse_str("0x123456ABCDEF")
+                .unwrap()
+                .to_hexadecimal()
+        );
+        assert_eq!(
+            "1234.56ab.cdef",
+            MacAddress::parse_str("1234.56AB.CDEF")
+                .unwrap()
+                .to_dot_string()
+        );
+        assert_eq!(
+            "12:34:56:ab:cd:ef",
+            MacAddress::parse_str("12:34:56:AB:CD:EF")
+                .unwrap()
+                .to_hex_string()
+        );
+        assert_eq!(
+            "12-34-56-ab-cd-ef",
+            MacAddress::parse_str("12-34-56-AB-CD-EF")
+                .unwrap()
+                .to_canonical()
+        );
+        // Test error parsing
+        assert_eq!(MacAddress::parse_str(""), Err(InvalidLength(0)));
+        assert_eq!(MacAddress::parse_str("0"), Err(InvalidLength(1)));
+        assert_eq!(
+            MacAddress::parse_str("123456ABCDEF"),
+            Err(InvalidLength(12))
+        );
+        assert_eq!(
+            MacAddress::parse_str("1234567890ABCD"),
+            Err(InvalidLength(14))
+        );
+        assert_eq!(
+            MacAddress::parse_str("1234567890ABCDEF"),
+            Err(InvalidLength(16))
+        );
+        assert_eq!(
+            MacAddress::parse_str("01234567890ABCDEF"),
+            Err(InvalidLength(17))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x1234567890A"),
+            Err(InvalidLength(13))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x1234567890ABCDE"),
+            Err(InvalidLength(17))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x00:00:00:00:"),
+            Err(InvalidLength(14))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x00:00:00:00:00:"),
+            Err(InvalidLength(17))
+        );
+        assert_eq!(
+            MacAddress::parse_str("::::::::::::::"),
+            Err(InvalidLength(14))
+        );
+        assert_eq!(
+            MacAddress::parse_str(":::::::::::::::::"),
+            Err(InvalidLength(17))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x0x0x0x0x0x0x"),
+            Err(InvalidCharacter('x', 3))
+        );
+        assert_eq!(
+            MacAddress::parse_str("!0x00000000000"),
+            Err(InvalidCharacter('!', 0))
+        );
+        assert_eq!(
+            MacAddress::parse_str("0x00000000000!"),
+            Err(InvalidCharacter('!', 13))
+        );
+    }
+
+    #[test]
+    fn test_as_bytes() {
+        let mac = MacAddress::broadcast();
+        let bytes = mac.as_bytes();
+
+        assert!(bytes.len() == 6);
+        assert!(bytes.iter().all(|&b| b == 0xFF));
+    }
+
+    #[test]
+    fn test_compare() {
+        let m1 = MacAddress::nil();
+        let m2 = MacAddress::broadcast();
+        assert!(m1 == m1);
+        assert!(m2 == m2);
+        assert!(m1 != m2);
+        assert!(m2 != m1);
+    }
+
+    #[test]
+    fn test_clone() {
+        let m1 = MacAddress::parse_str("12:34:56:AB:CD:EF").unwrap();
+        let m2 = m1.clone();
+        assert!(m1 == m1);
+        assert!(m2 == m2);
+        assert!(m1 == m2);
+        assert!(m2 == m1);
+    }
+
+    #[test]
+    fn test_serialize() {
+        use rustc_serialize::json;
+
+        let mac = MacAddress::parse_str("12:34:56:AB:CD:EF").unwrap();
+        assert_eq!("\"12-34-56-ab-cd-ef\"", json::encode(&mac).unwrap());
+    }
+
+    #[test]
+    fn test_deserialize() {
+        use rustc_serialize::json;
+
+        let d = "\"12-34-56-AB-CD-EF\"";
+        let mac = MacAddress::parse_str("12:34:56:AB:CD:EF").unwrap();
+        assert_eq!(mac, json::decode(&d).unwrap());
+    }
+
+    #[test]
+    fn test_serialize_roundtrip() {
+        use rustc_serialize::json;
+
+        let m1 = MacAddress::parse_str("12:34:56:AB:CD:EF").unwrap();
+        let s = json::encode(&m1).unwrap();
+        let m2 = json::decode(&s).unwrap();
+        assert_eq!(m1, m2);
+    }
+}