[
  {
    "path": ".github/workflows/build-and-test.yml",
    "content": "name: Build & Test\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\nenv:\n  CARGO_TERM_COLOR: always\n\njobs:\n  build-and-test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Build\n        run: cargo build --verbose\n      - name: Run tests\n        run: cargo test --verbose\n"
  },
  {
    "path": ".gitignore",
    "content": "target\nCargo.lock\n.vscode\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: rust\nrust:\n    - stable\n    - nightly\n\nscript:\n    - cargo test -v\n    - cargo test --features \"tokio-codec\"\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nauthors = [\"Y. T. Chung <zonyitoo@gmail.com>\"]\nname = \"mqtt-protocol\"\nversion = \"0.12.0\"\nlicense = \"MIT/Apache-2.0\"\ndescription = \"MQTT Protocol Library\"\nkeywords = [\"mqtt\", \"protocol\"]\nrepository = \"https://github.com/zonyitoo/mqtt-rs\"\ndocumentation = \"https://docs.rs/mqtt-protocol\"\nedition = \"2018\"\n\n[dependencies]\nbyteorder = \"1.3\"\nlog = \"0.4\"\ntokio = { version = \"1\", optional = true }\ntokio-util = { version = \"0.6\", features = [\"codec\"], optional = true }\nbytes = { version = \"1.0\", optional = true }\nthiserror = \"1.0\"\n\n[dev-dependencies]\nclap = \"2\"\nenv_logger = \"0.8\"\ntokio = { version = \"1.0\", features = [\"macros\", \"rt-multi-thread\", \"net\", \"time\", \"io-util\"] }\nfutures = { version = \"0.3\" }\nuuid = { version = \"0.8\", features = [\"v4\"] }\n\n[features]\ntokio-codec = [\"tokio\", \"tokio-util\", \"bytes\"]\ndefault = []\n\n[lib]\nname = \"mqtt\"\n\n[[example]]\nname = \"sub-client-async\"\nrequired-features = [\"tokio\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Y. T. CHUNG <zonyitoo@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# MQTT-rs\n\n[![Build Status](https://img.shields.io/travis/zonyitoo/mqtt-rs.svg)](https://travis-ci.org/zonyitoo/mqtt-rs)\n![Build & Test](https://github.com/zonyitoo/mqtt-rs/workflows/Build%20&%20Test/badge.svg)\n[![License](https://img.shields.io/github/license/zonyitoo/mqtt-rs.svg)](https://github.com/zonyitoo/mqtt-rs)\n[![crates.io](https://img.shields.io/crates/v/mqtt-protocol.svg)](https://crates.io/crates/mqtt-protocol)\n[![dependency status](https://deps.rs/repo/github/zonyitoo/mqtt-rs/status.svg)](https://deps.rs/repo/github/zonyitoo/mqtt-rs)\n\nMQTT protocol library for Rust\n\n```toml\n[dependencies]\nmqtt-protocol = \"0.12\"\n```\n\n## Usage\n\n```rust\nextern crate mqtt;\n\nuse std::io::Cursor;\n\nuse mqtt::{Encodable, Decodable};\nuse mqtt::packet::{VariablePacket, PublishPacket, QoSWithPacketIdentifier};\nuse mqtt::TopicName;\n\nfn main() {\n    // Create a new Publish packet\n    let packet = PublishPacket::new(TopicName::new(\"mqtt/learning\").unwrap(),\n                                    QoSWithPacketIdentifier::Level2(10),\n                                    \"Hello MQTT!\");\n\n    // Encode\n    let mut buf = Vec::new();\n    packet.encode(&mut buf).unwrap();\n    println!(\"Encoded: {:?}\", buf);\n\n    // Decode it with known type\n    let mut dec_buf = Cursor::new(&buf[..]);\n    let decoded = PublishPacket::decode(&mut dec_buf).unwrap();\n    println!(\"Decoded: {:?}\", decoded);\n    assert_eq!(packet, decoded);\n\n    // Auto decode by the fixed header\n    let mut dec_buf = Cursor::new(&buf[..]);\n    let auto_decode = VariablePacket::decode(&mut dec_buf).unwrap();\n    println!(\"Variable packet decode: {:?}\", auto_decode);\n    assert_eq!(VariablePacket::PublishPacket(packet), auto_decode);\n}\n```\n\n## Note\n\n* Based on [MQTT 3.1.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)\n"
  },
  {
    "path": "examples/pub-client.rs",
    "content": "#[macro_use]\nextern crate log;\n\nuse std::env;\nuse std::io::{self, Write};\nuse std::net::TcpStream;\nuse std::thread;\n\nuse clap::{App, Arg};\n\nuse uuid::Uuid;\n\nuse mqtt::control::variable_header::ConnectReturnCode;\nuse mqtt::packet::*;\nuse mqtt::{Decodable, Encodable, QualityOfService};\nuse mqtt::{TopicFilter, TopicName};\n\nfn generate_client_id() -> String {\n    format!(\"/MQTT/rust/{}\", Uuid::new_v4())\n}\n\nfn main() {\n    // configure logging\n    env::set_var(\"RUST_LOG\", env::var_os(\"RUST_LOG\").unwrap_or_else(|| \"info\".into()));\n    env_logger::init();\n\n    let matches = App::new(\"sub-client\")\n        .author(\"Y. T. Chung <zonyitoo@gmail.com>\")\n        .arg(\n            Arg::with_name(\"SERVER\")\n                .short(\"S\")\n                .long(\"server\")\n                .takes_value(true)\n                .required(true)\n                .help(\"MQTT server address (host:port)\"),\n        )\n        .arg(\n            Arg::with_name(\"SUBSCRIBE\")\n                .short(\"s\")\n                .long(\"subscribe\")\n                .takes_value(true)\n                .multiple(true)\n                .required(true)\n                .help(\"Channel filter to subscribe\"),\n        )\n        .arg(\n            Arg::with_name(\"USER_NAME\")\n                .short(\"u\")\n                .long(\"username\")\n                .takes_value(true)\n                .help(\"Login user name\"),\n        )\n        .arg(\n            Arg::with_name(\"PASSWORD\")\n                .short(\"p\")\n                .long(\"password\")\n                .takes_value(true)\n                .help(\"Password\"),\n        )\n        .arg(\n            Arg::with_name(\"CLIENT_ID\")\n                .short(\"i\")\n                .long(\"client-identifier\")\n                .takes_value(true)\n                .help(\"Client identifier\"),\n        )\n        .get_matches();\n\n    let server_addr = matches.value_of(\"SERVER\").unwrap();\n    let client_id = matches\n        .value_of(\"CLIENT_ID\")\n        .map(|x| x.to_owned())\n        .unwrap_or_else(generate_client_id);\n    let channel_filters: Vec<(TopicFilter, QualityOfService)> = matches\n        .values_of(\"SUBSCRIBE\")\n        .unwrap()\n        .map(|c| (TopicFilter::new(c.to_string()).unwrap(), QualityOfService::Level0))\n        .collect();\n\n    info!(\"Connecting to {:?} ... \", server_addr);\n    let mut stream = TcpStream::connect(server_addr).unwrap();\n    info!(\"Connected!\");\n\n    info!(\"Client identifier {:?}\", client_id);\n    let mut conn = ConnectPacket::new(client_id);\n    conn.set_clean_session(true);\n    let mut buf = Vec::new();\n    conn.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    let connack = ConnackPacket::decode(&mut stream).unwrap();\n    trace!(\"CONNACK {:?}\", connack);\n\n    if connack.connect_return_code() != ConnectReturnCode::ConnectionAccepted {\n        panic!(\n            \"Failed to connect to server, return code {:?}\",\n            connack.connect_return_code()\n        );\n    }\n\n    info!(\"Applying channel filters {:?} ...\", channel_filters);\n    let sub = SubscribePacket::new(10, channel_filters);\n    let mut buf = Vec::new();\n    sub.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    let channels: Vec<TopicName> = matches\n        .values_of(\"SUBSCRIBE\")\n        .unwrap()\n        .map(|c| TopicName::new(c.to_string()).unwrap())\n        .collect();\n\n    let user_name = matches.value_of(\"USER_NAME\").unwrap_or(\"<anonym>\");\n\n    let mut cloned_stream = stream.try_clone().unwrap();\n    thread::spawn(move || {\n        loop {\n            let packet = match VariablePacket::decode(&mut cloned_stream) {\n                Ok(pk) => pk,\n                Err(err) => {\n                    error!(\"Error in receiving packet {:?}\", err);\n                    continue;\n                }\n            };\n            trace!(\"PACKET {:?}\", packet);\n\n            match packet {\n                VariablePacket::PingreqPacket(..) => {\n                    let pingresp = PingrespPacket::new();\n                    info!(\"Sending Ping response {:?}\", pingresp);\n                    pingresp.encode(&mut cloned_stream).unwrap();\n                }\n                VariablePacket::DisconnectPacket(..) => {\n                    break;\n                }\n                _ => {\n                    // Ignore other packets in pub client\n                }\n            }\n        }\n    });\n\n    let stdin = io::stdin();\n    loop {\n        print!(\"{}: \", user_name);\n        io::stdout().flush().unwrap();\n\n        let mut line = String::new();\n        stdin.read_line(&mut line).unwrap();\n\n        if line.trim_end() == \"\" {\n            continue;\n        }\n\n        let message = format!(\"{}: {}\", user_name, line.trim_end());\n\n        for chan in &channels {\n            // let publish_packet = PublishPacket::new(chan.clone(), QoSWithPacketIdentifier::Level0, message.clone());\n            let publish_packet = PublishPacketRef::new(chan, QoSWithPacketIdentifier::Level0, message.as_bytes());\n            let mut buf = Vec::new();\n            publish_packet.encode(&mut buf).unwrap();\n            stream.write_all(&buf[..]).unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/simple.rs",
    "content": "use std::io::Cursor;\n\nuse mqtt::packet::{PublishPacket, QoSWithPacketIdentifier, VariablePacket};\nuse mqtt::TopicName;\nuse mqtt::{Decodable, Encodable};\n\nfn main() {\n    // Create a new Publish packet\n    let packet = PublishPacket::new(\n        TopicName::new(\"mqtt/learning\").unwrap(),\n        QoSWithPacketIdentifier::Level2(10),\n        \"Hello MQTT!\",\n    );\n\n    // Encode\n    let mut buf = Vec::new();\n    packet.encode(&mut buf).unwrap();\n    println!(\"Encoded: {:?}\", buf);\n\n    // Decode it with known type\n    let mut dec_buf = Cursor::new(&buf[..]);\n    let decoded = PublishPacket::decode(&mut dec_buf).unwrap();\n    println!(\"Decoded: {:?}\", decoded);\n    assert_eq!(packet, decoded);\n\n    // Auto decode by the fixed header\n    let mut dec_buf = Cursor::new(&buf[..]);\n    let auto_decode = VariablePacket::decode(&mut dec_buf).unwrap();\n    println!(\"Variable packet decode: {:?}\", auto_decode);\n    assert_eq!(VariablePacket::PublishPacket(packet), auto_decode);\n}\n"
  },
  {
    "path": "examples/sub-client-async.rs",
    "content": "use std::env;\nuse std::io::Write;\nuse std::net;\nuse std::str;\nuse std::time::Duration;\n\nuse clap::{App, Arg};\nuse log::{error, info, trace};\n\nuse uuid::Uuid;\n\nuse tokio::io::AsyncWriteExt;\nuse tokio::net::TcpStream;\n\nuse mqtt::control::variable_header::ConnectReturnCode;\nuse mqtt::packet::*;\nuse mqtt::TopicFilter;\nuse mqtt::{Decodable, Encodable, QualityOfService};\n\nfn generate_client_id() -> String {\n    format!(\"/MQTT/rust/{}\", Uuid::new_v4())\n}\n\n#[tokio::main]\nasync fn main() {\n    // configure logging\n    env::set_var(\"RUST_LOG\", env::var_os(\"RUST_LOG\").unwrap_or_else(|| \"info\".into()));\n    env_logger::init();\n\n    let matches = App::new(\"sub-client\")\n        .author(\"Y. T. Chung <zonyitoo@gmail.com>\")\n        .arg(\n            Arg::with_name(\"SERVER\")\n                .short(\"S\")\n                .long(\"server\")\n                .takes_value(true)\n                .required(true)\n                .help(\"MQTT server address (host:port)\"),\n        )\n        .arg(\n            Arg::with_name(\"SUBSCRIBE\")\n                .short(\"s\")\n                .long(\"subscribe\")\n                .takes_value(true)\n                .multiple(true)\n                .required(true)\n                .help(\"Channel filter to subscribe\"),\n        )\n        .arg(\n            Arg::with_name(\"USER_NAME\")\n                .short(\"u\")\n                .long(\"username\")\n                .takes_value(true)\n                .help(\"Login user name\"),\n        )\n        .arg(\n            Arg::with_name(\"PASSWORD\")\n                .short(\"p\")\n                .long(\"password\")\n                .takes_value(true)\n                .help(\"Password\"),\n        )\n        .arg(\n            Arg::with_name(\"CLIENT_ID\")\n                .short(\"i\")\n                .long(\"client-identifier\")\n                .takes_value(true)\n                .help(\"Client identifier\"),\n        )\n        .get_matches();\n\n    let server_addr = matches.value_of(\"SERVER\").unwrap();\n    let client_id = matches\n        .value_of(\"CLIENT_ID\")\n        .map(|x| x.to_owned())\n        .unwrap_or_else(generate_client_id);\n    let channel_filters: Vec<(TopicFilter, QualityOfService)> = matches\n        .values_of(\"SUBSCRIBE\")\n        .unwrap()\n        .map(|c| (TopicFilter::new(c.to_string()).unwrap(), QualityOfService::Level0))\n        .collect();\n\n    let keep_alive = 10;\n\n    info!(\"Connecting to {:?} ... \", server_addr);\n    let mut stream = net::TcpStream::connect(server_addr).unwrap();\n    info!(\"Connected!\");\n\n    info!(\"Client identifier {:?}\", client_id);\n    let mut conn = ConnectPacket::new(client_id);\n    conn.set_clean_session(true);\n    conn.set_keep_alive(keep_alive);\n    let mut buf = Vec::new();\n    conn.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    let connack = ConnackPacket::decode(&mut stream).unwrap();\n    trace!(\"CONNACK {:?}\", connack);\n\n    if connack.connect_return_code() != ConnectReturnCode::ConnectionAccepted {\n        panic!(\n            \"Failed to connect to server, return code {:?}\",\n            connack.connect_return_code()\n        );\n    }\n\n    // const CHANNEL_FILTER: &'static str = \"typing-speed-test.aoeu.eu\";\n    info!(\"Applying channel filters {:?} ...\", channel_filters);\n    let sub = SubscribePacket::new(10, channel_filters);\n    let mut buf = Vec::new();\n    sub.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    loop {\n        let packet = match VariablePacket::decode(&mut stream) {\n            Ok(pk) => pk,\n            Err(err) => {\n                error!(\"Error in receiving packet {:?}\", err);\n                continue;\n            }\n        };\n        trace!(\"PACKET {:?}\", packet);\n\n        if let VariablePacket::SubackPacket(ref ack) = packet {\n            if ack.packet_identifier() != 10 {\n                panic!(\"SUBACK packet identifier not match\");\n            }\n\n            info!(\"Subscribed!\");\n            break;\n        }\n    }\n\n    // connection made, start the async work\n    stream.set_nonblocking(true).unwrap();\n    let mut stream = TcpStream::from_std(stream).unwrap();\n    let (mut mqtt_read, mut mqtt_write) = stream.split();\n\n    let ping_sender = async move {\n        loop {\n            info!(\"Sending PINGREQ to broker\");\n\n            let pingreq_packet = PingreqPacket::new();\n\n            let mut buf = Vec::new();\n            pingreq_packet.encode(&mut buf).unwrap();\n            mqtt_write.write_all(&buf).await.unwrap();\n\n            tokio::time::sleep(Duration::from_secs(keep_alive as u64 / 2)).await;\n        }\n    };\n\n    let receiver = async move {\n        while let Ok(packet) = VariablePacket::parse(&mut mqtt_read).await {\n            trace!(\"PACKET {:?}\", packet);\n\n            match packet {\n                VariablePacket::PingrespPacket(..) => {\n                    info!(\"Received PINGRESP from broker ..\");\n                }\n                VariablePacket::PublishPacket(ref publ) => {\n                    let msg = match str::from_utf8(publ.payload()) {\n                        Ok(msg) => msg,\n                        Err(err) => {\n                            error!(\"Failed to decode publish message {:?}\", err);\n                            continue;\n                        }\n                    };\n                    info!(\"PUBLISH ({}): {}\", publ.topic_name(), msg);\n                }\n                _ => {}\n            }\n        }\n    };\n\n    tokio::pin!(ping_sender);\n    tokio::pin!(receiver);\n\n    tokio::join!(ping_sender, receiver);\n}\n"
  },
  {
    "path": "examples/sub-client.rs",
    "content": "extern crate mqtt;\n#[macro_use]\nextern crate log;\nextern crate clap;\nextern crate env_logger;\nextern crate uuid;\n\nuse std::env;\nuse std::io::Write;\nuse std::net::TcpStream;\nuse std::str;\nuse std::thread;\nuse std::time::{Duration, Instant};\n\nuse clap::{App, Arg};\n\nuse uuid::Uuid;\n\nuse mqtt::control::variable_header::ConnectReturnCode;\nuse mqtt::packet::*;\nuse mqtt::TopicFilter;\nuse mqtt::{Decodable, Encodable, QualityOfService};\n\nfn generate_client_id() -> String {\n    format!(\"/MQTT/rust/{}\", Uuid::new_v4())\n}\n\nfn main() {\n    // configure logging\n    env::set_var(\"RUST_LOG\", env::var_os(\"RUST_LOG\").unwrap_or_else(|| \"info\".into()));\n    env_logger::init();\n\n    let matches = App::new(\"sub-client\")\n        .author(\"Y. T. Chung <zonyitoo@gmail.com>\")\n        .arg(\n            Arg::with_name(\"SERVER\")\n                .short(\"S\")\n                .long(\"server\")\n                .takes_value(true)\n                .required(true)\n                .help(\"MQTT server address (host:port)\"),\n        )\n        .arg(\n            Arg::with_name(\"SUBSCRIBE\")\n                .short(\"s\")\n                .long(\"subscribe\")\n                .takes_value(true)\n                .multiple(true)\n                .required(true)\n                .help(\"Channel filter to subscribe\"),\n        )\n        .arg(\n            Arg::with_name(\"USER_NAME\")\n                .short(\"u\")\n                .long(\"username\")\n                .takes_value(true)\n                .help(\"Login user name\"),\n        )\n        .arg(\n            Arg::with_name(\"PASSWORD\")\n                .short(\"p\")\n                .long(\"password\")\n                .takes_value(true)\n                .help(\"Password\"),\n        )\n        .arg(\n            Arg::with_name(\"CLIENT_ID\")\n                .short(\"i\")\n                .long(\"client-identifier\")\n                .takes_value(true)\n                .help(\"Client identifier\"),\n        )\n        .get_matches();\n\n    let server_addr = matches.value_of(\"SERVER\").unwrap();\n    let client_id = matches\n        .value_of(\"CLIENT_ID\")\n        .map(|x| x.to_owned())\n        .unwrap_or_else(generate_client_id);\n    let channel_filters: Vec<(TopicFilter, QualityOfService)> = matches\n        .values_of(\"SUBSCRIBE\")\n        .unwrap()\n        .map(|c| (TopicFilter::new(c.to_string()).unwrap(), QualityOfService::Level0))\n        .collect();\n\n    let keep_alive = 10;\n\n    info!(\"Connecting to {:?} ... \", server_addr);\n    let mut stream = TcpStream::connect(server_addr).unwrap();\n    info!(\"Connected!\");\n\n    info!(\"Client identifier {:?}\", client_id);\n    let mut conn = ConnectPacket::new(client_id);\n    conn.set_clean_session(true);\n    conn.set_keep_alive(keep_alive);\n    let mut buf = Vec::new();\n    conn.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    let connack = ConnackPacket::decode(&mut stream).unwrap();\n    trace!(\"CONNACK {:?}\", connack);\n\n    if connack.connect_return_code() != ConnectReturnCode::ConnectionAccepted {\n        panic!(\n            \"Failed to connect to server, return code {:?}\",\n            connack.connect_return_code()\n        );\n    }\n\n    // const CHANNEL_FILTER: &'static str = \"typing-speed-test.aoeu.eu\";\n    info!(\"Applying channel filters {:?} ...\", channel_filters);\n    let sub = SubscribePacket::new(10, channel_filters);\n    let mut buf = Vec::new();\n    sub.encode(&mut buf).unwrap();\n    stream.write_all(&buf[..]).unwrap();\n\n    loop {\n        let packet = match VariablePacket::decode(&mut stream) {\n            Ok(pk) => pk,\n            Err(err) => {\n                error!(\"Error in receiving packet {:?}\", err);\n                continue;\n            }\n        };\n        trace!(\"PACKET {:?}\", packet);\n\n        if let VariablePacket::SubackPacket(ref ack) = packet {\n            if ack.packet_identifier() != 10 {\n                panic!(\"SUBACK packet identifier not match\");\n            }\n\n            info!(\"Subscribed!\");\n            break;\n        }\n    }\n\n    let mut stream_clone = stream.try_clone().unwrap();\n    thread::spawn(move || {\n        let mut last_ping_time = Instant::now();\n        let mut next_ping_time = last_ping_time + Duration::from_secs((keep_alive as f32 * 0.9) as u64);\n        loop {\n            let current_timestamp = Instant::now();\n            if keep_alive > 0 && current_timestamp >= next_ping_time {\n                info!(\"Sending PINGREQ to broker\");\n\n                let pingreq_packet = PingreqPacket::new();\n\n                let mut buf = Vec::new();\n                pingreq_packet.encode(&mut buf).unwrap();\n                stream_clone.write_all(&buf[..]).unwrap();\n\n                last_ping_time = current_timestamp;\n                next_ping_time = last_ping_time + Duration::from_secs((keep_alive as f32 * 0.9) as u64);\n                thread::sleep(Duration::new((keep_alive / 2) as u64, 0));\n            }\n        }\n    });\n\n    loop {\n        let packet = match VariablePacket::decode(&mut stream) {\n            Ok(pk) => pk,\n            Err(err) => {\n                error!(\"Error in receiving packet {}\", err);\n                continue;\n            }\n        };\n        trace!(\"PACKET {:?}\", packet);\n\n        match packet {\n            VariablePacket::PingrespPacket(..) => {\n                info!(\"Receiving PINGRESP from broker ..\");\n            }\n            VariablePacket::PublishPacket(ref publ) => {\n                let msg = match str::from_utf8(publ.payload()) {\n                    Ok(msg) => msg,\n                    Err(err) => {\n                        error!(\"Failed to decode publish message {:?}\", err);\n                        continue;\n                    }\n                };\n                info!(\"PUBLISH ({}): {}\", publ.topic_name(), msg);\n            }\n            _ => {}\n        }\n    }\n}\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "edition = \"2018\"\nmax_width = 120\nreorder_imports = true\nuse_try_shorthand = true\n"
  },
  {
    "path": "src/control/fixed_header.rs",
    "content": "//! Fixed header in MQTT\n\nuse std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\n#[cfg(feature = \"tokio\")]\nuse tokio::io::{AsyncRead, AsyncReadExt};\n\nuse crate::control::packet_type::{PacketType, PacketTypeError};\nuse crate::{Decodable, Encodable};\n\n/// Fixed header for each MQTT control packet\n///\n/// Format:\n///\n/// ```plain\n/// 7                          3                          0\n/// +--------------------------+--------------------------+\n/// | MQTT Control Packet Type | Flags for each type      |\n/// +--------------------------+--------------------------+\n/// | Remaining Length ...                                |\n/// +-----------------------------------------------------+\n/// ```\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct FixedHeader {\n    /// Packet Type\n    pub packet_type: PacketType,\n\n    /// The Remaining Length is the number of bytes remaining within the current packet,\n    /// including data in the variable header and the payload. The Remaining Length does\n    /// not include the bytes used to encode the Remaining Length.\n    pub remaining_length: u32,\n}\n\nimpl FixedHeader {\n    pub fn new(packet_type: PacketType, remaining_length: u32) -> FixedHeader {\n        debug_assert!(remaining_length <= 0x0FFF_FFFF);\n        FixedHeader {\n            packet_type,\n            remaining_length,\n        }\n    }\n\n    #[cfg(feature = \"tokio\")]\n    /// Asynchronously parse a single fixed header from an AsyncRead type, such as a network\n    /// socket.\n    ///\n    /// This requires mqtt-rs to be built with `feature = \"tokio\"`\n    pub async fn parse<A: AsyncRead + Unpin>(rdr: &mut A) -> Result<Self, FixedHeaderError> {\n        let type_val = rdr.read_u8().await?;\n\n        let mut remaining_len = 0;\n        let mut i = 0;\n\n        loop {\n            let byte = rdr.read_u8().await?;\n\n            remaining_len |= (u32::from(byte) & 0x7F) << (7 * i);\n\n            if i >= 4 {\n                return Err(FixedHeaderError::MalformedRemainingLength);\n            }\n\n            if byte & 0x80 == 0 {\n                break;\n            } else {\n                i += 1;\n            }\n        }\n\n        match PacketType::from_u8(type_val) {\n            Ok(packet_type) => Ok(FixedHeader::new(packet_type, remaining_len)),\n            Err(PacketTypeError::ReservedType(ty, _)) => Err(FixedHeaderError::ReservedType(ty, remaining_len)),\n            Err(err) => Err(From::from(err)),\n        }\n    }\n}\n\nimpl Encodable for FixedHeader {\n    fn encode<W: Write>(&self, wr: &mut W) -> Result<(), io::Error> {\n        wr.write_u8(self.packet_type.to_u8())?;\n\n        let mut cur_len = self.remaining_length;\n        loop {\n            let mut byte = (cur_len & 0x7F) as u8;\n            cur_len >>= 7;\n\n            if cur_len > 0 {\n                byte |= 0x80;\n            }\n\n            wr.write_u8(byte)?;\n\n            if cur_len == 0 {\n                break;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        let rem_size = if self.remaining_length >= 2_097_152 {\n            4\n        } else if self.remaining_length >= 16_384 {\n            3\n        } else if self.remaining_length >= 128 {\n            2\n        } else {\n            1\n        };\n        1 + rem_size\n    }\n}\n\nimpl Decodable for FixedHeader {\n    type Error = FixedHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(rdr: &mut R, _rest: ()) -> Result<FixedHeader, FixedHeaderError> {\n        let type_val = rdr.read_u8()?;\n        let remaining_len = {\n            let mut cur = 0u32;\n            for i in 0.. {\n                let byte = rdr.read_u8()?;\n                cur |= ((byte as u32) & 0x7F) << (7 * i);\n\n                if i >= 4 {\n                    return Err(FixedHeaderError::MalformedRemainingLength);\n                }\n\n                if byte & 0x80 == 0 {\n                    break;\n                }\n            }\n\n            cur\n        };\n\n        match PacketType::from_u8(type_val) {\n            Ok(packet_type) => Ok(FixedHeader::new(packet_type, remaining_len)),\n            Err(PacketTypeError::ReservedType(ty, _)) => Err(FixedHeaderError::ReservedType(ty, remaining_len)),\n            Err(err) => Err(From::from(err)),\n        }\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum FixedHeaderError {\n    #[error(\"malformed remaining length\")]\n    MalformedRemainingLength,\n    #[error(\"reserved header ({0}, {1})\")]\n    ReservedType(u8, u32),\n    #[error(transparent)]\n    PacketTypeError(#[from] PacketTypeError),\n    #[error(transparent)]\n    IoError(#[from] io::Error),\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use crate::control::packet_type::{ControlType, PacketType};\n    use crate::{Decodable, Encodable};\n    use std::io::Cursor;\n\n    #[test]\n    fn test_encode_fixed_header() {\n        let header = FixedHeader::new(PacketType::with_default(ControlType::Connect), 321);\n        let mut buf = Vec::new();\n        header.encode(&mut buf).unwrap();\n\n        let expected = b\"\\x10\\xc1\\x02\";\n        assert_eq!(&expected[..], &buf[..]);\n    }\n\n    #[test]\n    fn test_decode_fixed_header() {\n        let stream = b\"\\x10\\xc1\\x02\";\n        let mut cursor = Cursor::new(&stream[..]);\n        let header = FixedHeader::decode(&mut cursor).unwrap();\n        assert_eq!(header.packet_type, PacketType::with_default(ControlType::Connect));\n        assert_eq!(header.remaining_length, 321);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_decode_too_long_fixed_header() {\n        let stream = b\"\\x10\\x80\\x80\\x80\\x80\\x02\";\n        let mut cursor = Cursor::new(&stream[..]);\n        FixedHeader::decode(&mut cursor).unwrap();\n    }\n}\n"
  },
  {
    "path": "src/control/mod.rs",
    "content": "//! Control packets\n\npub use self::fixed_header::FixedHeader;\npub use self::packet_type::{ControlType, PacketType};\npub use self::variable_header::*;\n\npub mod fixed_header;\npub mod packet_type;\npub mod variable_header;\n"
  },
  {
    "path": "src/control/packet_type.rs",
    "content": "//! Packet types\n\nuse crate::qos::QualityOfService;\n\n/// Packet type\n// INVARIANT: the high 4 bits of the byte must be a valid control type\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub struct PacketType(u8);\n\n/// Defined control types\n#[rustfmt::skip]\n#[repr(u8)]\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub enum ControlType {\n    /// Client request to connect to Server\n    Connect                         = value::CONNECT,\n\n    /// Connect acknowledgment\n    ConnectAcknowledgement          = value::CONNACK,\n\n    /// Publish message\n    Publish                         = value::PUBLISH,\n\n    /// Publish acknowledgment\n    PublishAcknowledgement          = value::PUBACK,\n\n    /// Publish received (assured delivery part 1)\n    PublishReceived                 = value::PUBREC,\n\n    /// Publish release (assured delivery part 2)\n    PublishRelease                  = value::PUBREL,\n\n    /// Publish complete (assured delivery part 3)\n    PublishComplete                 = value::PUBCOMP,\n\n    /// Client subscribe request\n    Subscribe                       = value::SUBSCRIBE,\n\n    /// Subscribe acknowledgment\n    SubscribeAcknowledgement        = value::SUBACK,\n\n    /// Unsubscribe request\n    Unsubscribe                     = value::UNSUBSCRIBE,\n\n    /// Unsubscribe acknowledgment\n    UnsubscribeAcknowledgement      = value::UNSUBACK,\n\n    /// PING request\n    PingRequest                     = value::PINGREQ,\n\n    /// PING response\n    PingResponse                    = value::PINGRESP,\n\n    /// Client is disconnecting\n    Disconnect                      = value::DISCONNECT,\n}\n\nimpl ControlType {\n    #[inline]\n    fn default_flags(self) -> u8 {\n        match self {\n            ControlType::Connect => 0,\n            ControlType::ConnectAcknowledgement => 0,\n\n            ControlType::Publish => 0,\n            ControlType::PublishAcknowledgement => 0,\n            ControlType::PublishReceived => 0,\n            ControlType::PublishRelease => 0b0010,\n            ControlType::PublishComplete => 0,\n\n            ControlType::Subscribe => 0b0010,\n            ControlType::SubscribeAcknowledgement => 0,\n\n            ControlType::Unsubscribe => 0b0010,\n            ControlType::UnsubscribeAcknowledgement => 0,\n\n            ControlType::PingRequest => 0,\n            ControlType::PingResponse => 0,\n\n            ControlType::Disconnect => 0,\n        }\n    }\n}\n\nimpl PacketType {\n    /// Creates a packet type. Returns None if `flags` is an invalid value for the given\n    /// ControlType as defined by the [MQTT spec].\n    ///\n    /// [MQTT spec]: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Table_2.2_-\n    pub fn new(t: ControlType, flags: u8) -> Result<PacketType, InvalidFlag> {\n        let flags_ok = match t {\n            ControlType::Publish => {\n                let qos = (flags & 0b0110) >> 1;\n                matches!(qos, 0 | 1 | 2)\n            }\n            _ => t.default_flags() == flags,\n        };\n        if flags_ok {\n            Ok(PacketType::new_unchecked(t, flags))\n        } else {\n            Err(InvalidFlag(t, flags))\n        }\n    }\n\n    #[inline]\n    fn new_unchecked(t: ControlType, flags: u8) -> PacketType {\n        let byte = (t as u8) << 4 | (flags & 0x0F);\n        #[allow(unused_unsafe)]\n        unsafe {\n            // SAFETY: just constructed from a valid ControlType\n            PacketType(byte)\n        }\n    }\n\n    /// Creates a packet type with default flags\n    ///\n    /// <http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Table_2.2_->\n    #[inline]\n    pub fn with_default(t: ControlType) -> PacketType {\n        let flags = t.default_flags();\n        PacketType::new_unchecked(t, flags)\n    }\n\n    pub(crate) fn publish(qos: QualityOfService) -> PacketType {\n        PacketType::new_unchecked(ControlType::Publish, (qos as u8) << 1)\n    }\n\n    #[inline]\n    pub(crate) fn update_flags(&mut self, upd: impl FnOnce(u8) -> u8) {\n        let flags = upd(self.flags());\n        self.0 = (self.0 & !0x0F) | (flags & 0x0F)\n    }\n\n    /// To code\n    #[inline]\n    pub fn to_u8(self) -> u8 {\n        self.0\n    }\n\n    /// From code\n    pub fn from_u8(val: u8) -> Result<PacketType, PacketTypeError> {\n        let type_val = val >> 4;\n        let flags = val & 0x0F;\n\n        let control_type = get_control_type(type_val).ok_or(PacketTypeError::ReservedType(type_val, flags))?;\n        Ok(PacketType::new(control_type, flags)?)\n    }\n\n    #[inline]\n    pub fn control_type(self) -> ControlType {\n        get_control_type(self.0 >> 4).unwrap_or_else(|| {\n            // SAFETY: this is maintained by the invariant for PacketType\n            unsafe { std::hint::unreachable_unchecked() }\n        })\n    }\n\n    #[inline]\n    pub fn flags(self) -> u8 {\n        self.0 & 0x0F\n    }\n}\n\n#[inline]\nfn get_control_type(val: u8) -> Option<ControlType> {\n    let typ = match val {\n        value::CONNECT => ControlType::Connect,\n        value::CONNACK => ControlType::ConnectAcknowledgement,\n\n        value::PUBLISH => ControlType::Publish,\n        value::PUBACK => ControlType::PublishAcknowledgement,\n        value::PUBREC => ControlType::PublishReceived,\n        value::PUBREL => ControlType::PublishRelease,\n        value::PUBCOMP => ControlType::PublishComplete,\n\n        value::SUBSCRIBE => ControlType::Subscribe,\n        value::SUBACK => ControlType::SubscribeAcknowledgement,\n\n        value::UNSUBSCRIBE => ControlType::Unsubscribe,\n        value::UNSUBACK => ControlType::UnsubscribeAcknowledgement,\n\n        value::PINGREQ => ControlType::PingRequest,\n        value::PINGRESP => ControlType::PingResponse,\n\n        value::DISCONNECT => ControlType::Disconnect,\n\n        _ => return None,\n    };\n    Some(typ)\n}\n\n/// Parsing packet type errors\n#[derive(Debug, thiserror::Error)]\npub enum PacketTypeError {\n    #[error(\"reserved type {0:?} (flags {1:#X})\")]\n    ReservedType(u8, u8),\n    #[error(transparent)]\n    InvalidFlag(#[from] InvalidFlag),\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"invalid flag for {0:?} ({1:#X})\")]\npub struct InvalidFlag(pub ControlType, pub u8);\n\n#[rustfmt::skip]\nmod value {\n    pub const CONNECT:     u8 = 1;\n    pub const CONNACK:     u8 = 2;\n    pub const PUBLISH:     u8 = 3;\n    pub const PUBACK:      u8 = 4;\n    pub const PUBREC:      u8 = 5;\n    pub const PUBREL:      u8 = 6;\n    pub const PUBCOMP:     u8 = 7;\n    pub const SUBSCRIBE:   u8 = 8;\n    pub const SUBACK:      u8 = 9;\n    pub const UNSUBSCRIBE: u8 = 10;\n    pub const UNSUBACK:    u8 = 11;\n    pub const PINGREQ:     u8 = 12;\n    pub const PINGRESP:    u8 = 13;\n    pub const DISCONNECT:  u8 = 14;\n}\n"
  },
  {
    "path": "src/control/variable_header/connect_ack_flags.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\n/// Flags in `CONNACK` packet\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub struct ConnackFlags {\n    pub session_present: bool,\n}\n\nimpl ConnackFlags {\n    pub fn empty() -> ConnackFlags {\n        ConnackFlags { session_present: false }\n    }\n}\n\nimpl Encodable for ConnackFlags {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        let code = self.session_present as u8;\n        writer.write_u8(code)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        1\n    }\n}\n\nimpl Decodable for ConnackFlags {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<ConnackFlags, VariableHeaderError> {\n        let code = reader.read_u8()?;\n        if code & !1 != 0 {\n            return Err(VariableHeaderError::InvalidReservedFlag);\n        }\n\n        Ok(ConnackFlags {\n            session_present: code == 1,\n        })\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/connect_flags.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\n/// Flags for `CONNECT` packet\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub struct ConnectFlags {\n    pub user_name: bool,\n    pub password: bool,\n    pub will_retain: bool,\n    pub will_qos: u8,\n    pub will_flag: bool,\n    pub clean_session: bool,\n    // We never use this, but must decode because brokers must verify it's zero per [MQTT-3.1.2-3]\n    pub reserved: bool,\n}\n\nimpl ConnectFlags {\n    pub fn empty() -> ConnectFlags {\n        ConnectFlags {\n            user_name: false,\n            password: false,\n            will_retain: false,\n            will_qos: 0,\n            will_flag: false,\n            clean_session: false,\n            reserved: false,\n        }\n    }\n}\n\nimpl Encodable for ConnectFlags {\n    #[rustfmt::skip]\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        let code = ((self.user_name as u8) << 7)\n            | ((self.password as u8) << 6)\n            | ((self.will_retain as u8) << 5)\n            | ((self.will_qos) << 3)\n            | ((self.will_flag as u8) << 2)\n            | ((self.clean_session as u8) << 1);\n\n        writer.write_u8(code)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        1\n    }\n}\n\nimpl Decodable for ConnectFlags {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<ConnectFlags, VariableHeaderError> {\n        let code = reader.read_u8()?;\n        if code & 1 != 0 {\n            return Err(VariableHeaderError::InvalidReservedFlag);\n        }\n\n        Ok(ConnectFlags {\n            user_name: (code & 0b1000_0000) != 0,\n            password: (code & 0b0100_0000) != 0,\n            will_retain: (code & 0b0010_0000) != 0,\n            will_qos: (code & 0b0001_1000) >> 3,\n            will_flag: (code & 0b0000_0100) != 0,\n            clean_session: (code & 0b0000_0010) != 0,\n            reserved: (code & 0b0000_0001) != 0,\n        })\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/connect_ret_code.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\npub const CONNECTION_ACCEPTED: u8 = 0x00;\npub const UNACCEPTABLE_PROTOCOL_VERSION: u8 = 0x01;\npub const IDENTIFIER_REJECTED: u8 = 0x02;\npub const SERVICE_UNAVAILABLE: u8 = 0x03;\npub const BAD_USER_NAME_OR_PASSWORD: u8 = 0x04;\npub const NOT_AUTHORIZED: u8 = 0x05;\n\n/// Return code for `CONNACK` packet\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub enum ConnectReturnCode {\n    ConnectionAccepted,\n    UnacceptableProtocolVersion,\n    IdentifierRejected,\n    ServiceUnavailable,\n    BadUserNameOrPassword,\n    NotAuthorized,\n    Reserved(u8),\n}\n\nimpl ConnectReturnCode {\n    /// Get the code\n    pub fn to_u8(self) -> u8 {\n        match self {\n            ConnectReturnCode::ConnectionAccepted => CONNECTION_ACCEPTED,\n            ConnectReturnCode::UnacceptableProtocolVersion => UNACCEPTABLE_PROTOCOL_VERSION,\n            ConnectReturnCode::IdentifierRejected => IDENTIFIER_REJECTED,\n            ConnectReturnCode::ServiceUnavailable => SERVICE_UNAVAILABLE,\n            ConnectReturnCode::BadUserNameOrPassword => BAD_USER_NAME_OR_PASSWORD,\n            ConnectReturnCode::NotAuthorized => NOT_AUTHORIZED,\n            ConnectReturnCode::Reserved(r) => r,\n        }\n    }\n\n    /// Create `ConnectReturnCode` from code\n    pub fn from_u8(code: u8) -> ConnectReturnCode {\n        match code {\n            CONNECTION_ACCEPTED => ConnectReturnCode::ConnectionAccepted,\n            UNACCEPTABLE_PROTOCOL_VERSION => ConnectReturnCode::UnacceptableProtocolVersion,\n            IDENTIFIER_REJECTED => ConnectReturnCode::IdentifierRejected,\n            SERVICE_UNAVAILABLE => ConnectReturnCode::ServiceUnavailable,\n            BAD_USER_NAME_OR_PASSWORD => ConnectReturnCode::BadUserNameOrPassword,\n            NOT_AUTHORIZED => ConnectReturnCode::NotAuthorized,\n            _ => ConnectReturnCode::Reserved(code),\n        }\n    }\n}\n\nimpl Encodable for ConnectReturnCode {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        writer.write_u8(self.to_u8())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        1\n    }\n}\n\nimpl Decodable for ConnectReturnCode {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<ConnectReturnCode, VariableHeaderError> {\n        reader.read_u8().map(ConnectReturnCode::from_u8).map_err(From::from)\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/keep_alive.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\n/// Keep alive time interval\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub struct KeepAlive(pub u16);\n\nimpl Encodable for KeepAlive {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        writer.write_u16::<BigEndian>(self.0)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        2\n    }\n}\n\nimpl Decodable for KeepAlive {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<KeepAlive, VariableHeaderError> {\n        reader.read_u16::<BigEndian>().map(KeepAlive).map_err(From::from)\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/mod.rs",
    "content": "//! Variable header in MQTT\n\nuse std::io;\nuse std::string::FromUtf8Error;\n\nuse crate::topic_name::{TopicNameDecodeError, TopicNameError};\n\npub use self::connect_ack_flags::ConnackFlags;\npub use self::connect_flags::ConnectFlags;\npub use self::connect_ret_code::ConnectReturnCode;\npub use self::keep_alive::KeepAlive;\npub use self::packet_identifier::PacketIdentifier;\npub use self::protocol_level::ProtocolLevel;\npub use self::protocol_name::ProtocolName;\npub use self::topic_name::TopicNameHeader;\n\nmod connect_ack_flags;\nmod connect_flags;\nmod connect_ret_code;\nmod keep_alive;\nmod packet_identifier;\npub mod protocol_level;\nmod protocol_name;\nmod topic_name;\n\n/// Errors while decoding variable header\n#[derive(Debug, thiserror::Error)]\npub enum VariableHeaderError {\n    #[error(transparent)]\n    IoError(#[from] io::Error),\n    #[error(\"invalid reserved flags\")]\n    InvalidReservedFlag,\n    #[error(transparent)]\n    FromUtf8Error(#[from] FromUtf8Error),\n    #[error(transparent)]\n    TopicNameError(#[from] TopicNameError),\n    #[error(\"invalid protocol version\")]\n    InvalidProtocolVersion,\n}\n\nimpl From<TopicNameDecodeError> for VariableHeaderError {\n    fn from(err: TopicNameDecodeError) -> VariableHeaderError {\n        match err {\n            TopicNameDecodeError::IoError(e) => Self::IoError(e),\n            TopicNameDecodeError::InvalidTopicName(e) => Self::TopicNameError(e),\n        }\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/packet_identifier.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\n/// Packet identifier\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub struct PacketIdentifier(pub u16);\n\nimpl Encodable for PacketIdentifier {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        writer.write_u16::<BigEndian>(self.0)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        2\n    }\n}\n\nimpl Decodable for PacketIdentifier {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<PacketIdentifier, VariableHeaderError> {\n        reader.read_u16::<BigEndian>().map(PacketIdentifier).map_err(From::from)\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/protocol_level.rs",
    "content": "//! Protocol level header\n\nuse std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\npub const SPEC_3_1_0: u8 = 0x03;\npub const SPEC_3_1_1: u8 = 0x04;\npub const SPEC_5_0: u8 = 0x05;\n\n/// Protocol level in MQTT (`0x04` in v3.1.1)\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\n#[repr(u8)]\npub enum ProtocolLevel {\n    Version310 = SPEC_3_1_0,\n    Version311 = SPEC_3_1_1,\n    Version50 = SPEC_5_0,\n}\n\nimpl Encodable for ProtocolLevel {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        writer.write_u8(*self as u8)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        1\n    }\n}\n\nimpl Decodable for ProtocolLevel {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<ProtocolLevel, VariableHeaderError> {\n        reader\n            .read_u8()\n            .map_err(From::from)\n            .map(ProtocolLevel::from_u8)\n            .and_then(|x| x.ok_or(VariableHeaderError::InvalidProtocolVersion))\n    }\n}\n\nimpl ProtocolLevel {\n    pub fn from_u8(n: u8) -> Option<ProtocolLevel> {\n        match n {\n            SPEC_3_1_0 => Some(ProtocolLevel::Version310),\n            SPEC_3_1_1 => Some(ProtocolLevel::Version311),\n            SPEC_5_0 => Some(ProtocolLevel::Version50),\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/protocol_name.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::{Decodable, Encodable};\n\n/// Protocol name in variable header\n///\n/// # Example\n///\n/// ```plain\n/// 7                          3                          0\n/// +--------------------------+--------------------------+\n/// | Length MSB (0)                                      |\n/// | Length LSB (4)                                      |\n/// | 0100                     | 1101                     | 'M'\n/// | 0101                     | 0001                     | 'Q'\n/// | 0101                     | 0100                     | 'T'\n/// | 0101                     | 0100                     | 'T'\n/// +--------------------------+--------------------------+\n/// ```\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct ProtocolName(pub String);\n\nimpl Encodable for ProtocolName {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self.0[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self.0[..]).encoded_length()\n    }\n}\n\nimpl Decodable for ProtocolName {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<ProtocolName, VariableHeaderError> {\n        Ok(ProtocolName(Decodable::decode(reader)?))\n    }\n}\n"
  },
  {
    "path": "src/control/variable_header/topic_name.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::topic_name::TopicName;\nuse crate::{Decodable, Encodable};\n\n/// Topic name wrapper\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct TopicNameHeader(TopicName);\n\nimpl TopicNameHeader {\n    pub fn new(topic_name: String) -> Result<TopicNameHeader, VariableHeaderError> {\n        match TopicName::new(topic_name) {\n            Ok(h) => Ok(TopicNameHeader(h)),\n            Err(err) => Err(VariableHeaderError::TopicNameError(err)),\n        }\n    }\n}\n\nimpl From<TopicNameHeader> for TopicName {\n    fn from(hdr: TopicNameHeader) -> Self {\n        hdr.0\n    }\n}\n\nimpl Encodable for TopicNameHeader {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self.0[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self.0[..]).encoded_length()\n    }\n}\n\nimpl Decodable for TopicNameHeader {\n    type Error = VariableHeaderError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<TopicNameHeader, VariableHeaderError> {\n        TopicNameHeader::new(Decodable::decode(reader)?)\n    }\n}\n"
  },
  {
    "path": "src/encodable.rs",
    "content": "//! Encodable traits\n\nuse std::convert::Infallible;\nuse std::error::Error;\n\nuse std::io::{self, Read, Write};\nuse std::marker::Sized;\n\nuse byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};\n\n/// Methods for encoding an Object to bytes according to MQTT specification\npub trait Encodable {\n    /// Encodes to writer\n    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()>;\n    /// Length of bytes after encoded\n    fn encoded_length(&self) -> u32;\n}\n\n// impl<T: Encodable> Encodable for &T {\n//     fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {\n//         (**self).encode(writer)\n//     }\n//     fn encoded_length(&self) -> u32 {\n//         (**self).encoded_length()\n//     }\n// }\n\nimpl<T: Encodable> Encodable for Option<T> {\n    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {\n        if let Some(this) = self {\n            this.encode(writer)?\n        }\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.as_ref().map_or(0, |x| x.encoded_length())\n    }\n}\n\n/// Methods for decoding bytes to an Object according to MQTT specification\npub trait Decodable: Sized {\n    type Error: Error;\n    type Cond;\n\n    /// Decodes object from reader\n    fn decode<R: Read>(reader: &mut R) -> Result<Self, Self::Error>\n    where\n        Self::Cond: Default,\n    {\n        Self::decode_with(reader, Default::default())\n    }\n\n    /// Decodes object with additional data (or hints)\n    fn decode_with<R: Read>(reader: &mut R, cond: Self::Cond) -> Result<Self, Self::Error>;\n}\n\nimpl<'a> Encodable for &'a str {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        assert!(self.as_bytes().len() <= u16::max_value() as usize);\n\n        writer\n            .write_u16::<BigEndian>(self.as_bytes().len() as u16)\n            .and_then(|_| writer.write_all(self.as_bytes()))\n    }\n\n    fn encoded_length(&self) -> u32 {\n        2 + self.as_bytes().len() as u32\n    }\n}\n\nimpl<'a> Encodable for &'a [u8] {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        writer.write_all(self)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.len() as u32\n    }\n}\n\nimpl Encodable for String {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self[..]).encoded_length()\n    }\n}\n\nimpl Decodable for String {\n    type Error = io::Error;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<String, io::Error> {\n        let VarBytes(buf) = VarBytes::decode(reader)?;\n\n        String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))\n    }\n}\n\nimpl Encodable for Vec<u8> {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self[..]).encoded_length()\n    }\n}\n\nimpl Decodable for Vec<u8> {\n    type Error = io::Error;\n    type Cond = Option<u32>;\n\n    fn decode_with<R: Read>(reader: &mut R, length: Option<u32>) -> Result<Vec<u8>, io::Error> {\n        match length {\n            Some(length) => {\n                let mut buf = Vec::with_capacity(length as usize);\n                reader.take(length.into()).read_to_end(&mut buf)?;\n                Ok(buf)\n            }\n            None => {\n                let mut buf = Vec::new();\n                reader.read_to_end(&mut buf)?;\n                Ok(buf)\n            }\n        }\n    }\n}\n\nimpl Encodable for () {\n    fn encode<W: Write>(&self, _: &mut W) -> Result<(), io::Error> {\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        0\n    }\n}\n\nimpl Decodable for () {\n    type Error = Infallible;\n    type Cond = ();\n\n    fn decode_with<R: Read>(_: &mut R, _: ()) -> Result<(), Self::Error> {\n        Ok(())\n    }\n}\n\n/// Bytes that encoded with length\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct VarBytes(pub Vec<u8>);\n\nimpl Encodable for VarBytes {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        assert!(self.0.len() <= u16::max_value() as usize);\n        let len = self.0.len() as u16;\n        writer.write_u16::<BigEndian>(len)?;\n        writer.write_all(&self.0)?;\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        2 + self.0.len() as u32\n    }\n}\n\nimpl Decodable for VarBytes {\n    type Error = io::Error;\n    type Cond = ();\n    fn decode_with<R: Read>(reader: &mut R, _: ()) -> Result<VarBytes, io::Error> {\n        let length = reader.read_u16::<BigEndian>()?;\n        let mut buf = Vec::with_capacity(length as usize);\n        reader.take(length.into()).read_to_end(&mut buf)?;\n        Ok(VarBytes(buf))\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use std::io::Cursor;\n\n    #[test]\n    fn varbyte_encode() {\n        let test_var = vec![0, 1, 2, 3, 4, 5];\n        let bytes = VarBytes(test_var);\n\n        assert_eq!(bytes.encoded_length() as usize, 2 + 6);\n\n        let mut buf = Vec::new();\n        bytes.encode(&mut buf).unwrap();\n\n        assert_eq!(&buf, &[0, 6, 0, 1, 2, 3, 4, 5]);\n\n        let mut reader = Cursor::new(buf);\n        let decoded = VarBytes::decode(&mut reader).unwrap();\n\n        assert_eq!(decoded, bytes);\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "//! MQTT protocol utilities library\n//!\n//! Strictly implements protocol of [MQTT v3.1.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)\n//!\n//! ## Usage\n//!\n//! ```rust\n//! use std::io::Cursor;\n//!\n//! use mqtt::{Encodable, Decodable};\n//! use mqtt::packet::{VariablePacket, PublishPacket, QoSWithPacketIdentifier};\n//! use mqtt::TopicName;\n//!\n//! // Create a new Publish packet\n//! let packet = PublishPacket::new(TopicName::new(\"mqtt/learning\").unwrap(),\n//!                                 QoSWithPacketIdentifier::Level2(10),\n//!                                 b\"Hello MQTT!\".to_vec());\n//!\n//! // Encode\n//! let mut buf = Vec::new();\n//! packet.encode(&mut buf).unwrap();\n//! println!(\"Encoded: {:?}\", buf);\n//!\n//! // Decode it with known type\n//! let mut dec_buf = Cursor::new(&buf[..]);\n//! let decoded = PublishPacket::decode(&mut dec_buf).unwrap();\n//! println!(\"Decoded: {:?}\", decoded);\n//! assert_eq!(packet, decoded);\n//!\n//! // Auto decode by the fixed header\n//! let mut dec_buf = Cursor::new(&buf[..]);\n//! let auto_decode = VariablePacket::decode(&mut dec_buf).unwrap();\n//! println!(\"Variable packet decode: {:?}\", auto_decode);\n//! assert_eq!(VariablePacket::PublishPacket(packet), auto_decode);\n//! ```\n\npub use self::encodable::{Decodable, Encodable};\npub use self::qos::QualityOfService;\npub use self::topic_filter::{TopicFilter, TopicFilterRef};\npub use self::topic_name::{TopicName, TopicNameRef};\n\npub mod control;\npub mod encodable;\npub mod packet;\npub mod qos;\npub mod topic_filter;\npub mod topic_name;\n"
  },
  {
    "path": "src/packet/connack.rs",
    "content": "//! CONNACK\n\nuse std::io::Read;\n\nuse crate::control::variable_header::{ConnackFlags, ConnectReturnCode};\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `CONNACK` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct ConnackPacket {\n    fixed_header: FixedHeader,\n    flags: ConnackFlags,\n    ret_code: ConnectReturnCode,\n}\n\nencodable_packet!(ConnackPacket(flags, ret_code));\n\nimpl ConnackPacket {\n    pub fn new(session_present: bool, ret_code: ConnectReturnCode) -> ConnackPacket {\n        ConnackPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::ConnectAcknowledgement), 2),\n            flags: ConnackFlags { session_present },\n            ret_code,\n        }\n    }\n\n    pub fn connack_flags(&self) -> ConnackFlags {\n        self.flags\n    }\n\n    pub fn connect_return_code(&self) -> ConnectReturnCode {\n        self.ret_code\n    }\n}\n\nimpl DecodablePacket for ConnackPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let flags: ConnackFlags = Decodable::decode(reader)?;\n        let code: ConnectReturnCode = Decodable::decode(reader)?;\n\n        Ok(ConnackPacket {\n            fixed_header,\n            flags,\n            ret_code: code,\n        })\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use std::io::Cursor;\n\n    use crate::control::variable_header::ConnectReturnCode;\n    use crate::{Decodable, Encodable};\n\n    #[test]\n    pub fn test_connack_packet_basic() {\n        let packet = ConnackPacket::new(false, ConnectReturnCode::IdentifierRejected);\n\n        let mut buf = Vec::new();\n        packet.encode(&mut buf).unwrap();\n\n        let mut decode_buf = Cursor::new(buf);\n        let decoded = ConnackPacket::decode(&mut decode_buf).unwrap();\n\n        assert_eq!(packet, decoded);\n    }\n}\n"
  },
  {
    "path": "src/packet/connect.rs",
    "content": "//! CONNECT\n\nuse std::io::{self, Read, Write};\n\nuse crate::control::variable_header::protocol_level::SPEC_3_1_1;\nuse crate::control::variable_header::{ConnectFlags, KeepAlive, ProtocolLevel, ProtocolName, VariableHeaderError};\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::encodable::VarBytes;\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::topic_name::{TopicName, TopicNameDecodeError, TopicNameError};\nuse crate::{Decodable, Encodable};\n\n/// `CONNECT` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct ConnectPacket {\n    fixed_header: FixedHeader,\n    protocol_name: ProtocolName,\n\n    protocol_level: ProtocolLevel,\n    flags: ConnectFlags,\n    keep_alive: KeepAlive,\n\n    payload: ConnectPacketPayload,\n}\n\nencodable_packet!(ConnectPacket(protocol_name, protocol_level, flags, keep_alive, payload));\n\nimpl ConnectPacket {\n    pub fn new<C>(client_identifier: C) -> ConnectPacket\n    where\n        C: Into<String>,\n    {\n        ConnectPacket::with_level(\"MQTT\", client_identifier, SPEC_3_1_1).expect(\"SPEC_3_1_1 should always be valid\")\n    }\n\n    pub fn with_level<P, C>(protoname: P, client_identifier: C, level: u8) -> Result<ConnectPacket, VariableHeaderError>\n    where\n        P: Into<String>,\n        C: Into<String>,\n    {\n        let protocol_level = ProtocolLevel::from_u8(level).ok_or(VariableHeaderError::InvalidProtocolVersion)?;\n        let mut pk = ConnectPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::Connect), 0),\n            protocol_name: ProtocolName(protoname.into()),\n            protocol_level,\n            flags: ConnectFlags::empty(),\n            keep_alive: KeepAlive(0),\n            payload: ConnectPacketPayload::new(client_identifier.into()),\n        };\n\n        pk.fix_header_remaining_len();\n\n        Ok(pk)\n    }\n\n    pub fn set_keep_alive(&mut self, keep_alive: u16) {\n        self.keep_alive = KeepAlive(keep_alive);\n    }\n\n    pub fn set_user_name(&mut self, name: Option<String>) {\n        self.flags.user_name = name.is_some();\n        self.payload.user_name = name;\n        self.fix_header_remaining_len();\n    }\n\n    pub fn set_will(&mut self, topic_message: Option<(TopicName, Vec<u8>)>) {\n        self.flags.will_flag = topic_message.is_some();\n\n        self.payload.will = topic_message.map(|(t, m)| (t, VarBytes(m)));\n\n        self.fix_header_remaining_len();\n    }\n\n    pub fn set_password(&mut self, password: Option<String>) {\n        self.flags.password = password.is_some();\n        self.payload.password = password;\n        self.fix_header_remaining_len();\n    }\n\n    pub fn set_client_identifier<I: Into<String>>(&mut self, id: I) {\n        self.payload.client_identifier = id.into();\n        self.fix_header_remaining_len();\n    }\n\n    pub fn set_will_retain(&mut self, will_retain: bool) {\n        self.flags.will_retain = will_retain;\n    }\n\n    pub fn set_will_qos(&mut self, will_qos: u8) {\n        assert!(will_qos <= 2);\n        self.flags.will_qos = will_qos;\n    }\n\n    pub fn set_clean_session(&mut self, clean_session: bool) {\n        self.flags.clean_session = clean_session;\n    }\n\n    pub fn user_name(&self) -> Option<&str> {\n        self.payload.user_name.as_ref().map(|x| &x[..])\n    }\n\n    pub fn password(&self) -> Option<&str> {\n        self.payload.password.as_ref().map(|x| &x[..])\n    }\n\n    pub fn will(&self) -> Option<(&str, &[u8])> {\n        self.payload.will.as_ref().map(|(topic, msg)| (&topic[..], &*msg.0))\n    }\n\n    pub fn will_retain(&self) -> bool {\n        self.flags.will_retain\n    }\n\n    pub fn will_qos(&self) -> u8 {\n        self.flags.will_qos\n    }\n\n    pub fn client_identifier(&self) -> &str {\n        &self.payload.client_identifier[..]\n    }\n\n    pub fn protocol_name(&self) -> &str {\n        &self.protocol_name.0\n    }\n\n    pub fn protocol_level(&self) -> ProtocolLevel {\n        self.protocol_level\n    }\n\n    pub fn clean_session(&self) -> bool {\n        self.flags.clean_session\n    }\n\n    pub fn keep_alive(&self) -> u16 {\n        self.keep_alive.0\n    }\n\n    /// Read back the \"reserved\" Connect flag bit 0. For compliant implementations this should\n    /// always be false.\n    pub fn reserved_flag(&self) -> bool {\n        self.flags.reserved\n    }\n}\n\nimpl DecodablePacket for ConnectPacket {\n    type DecodePacketError = ConnectPacketError;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let protoname: ProtocolName = Decodable::decode(reader)?;\n        let protocol_level: ProtocolLevel = Decodable::decode(reader)?;\n        let flags: ConnectFlags = Decodable::decode(reader)?;\n        let keep_alive: KeepAlive = Decodable::decode(reader)?;\n        let payload: ConnectPacketPayload =\n            Decodable::decode_with(reader, Some(flags)).map_err(PacketError::PayloadError)?;\n\n        Ok(ConnectPacket {\n            fixed_header,\n            protocol_name: protoname,\n            protocol_level,\n            flags,\n            keep_alive,\n            payload,\n        })\n    }\n}\n\n/// Payloads for connect packet\n#[derive(Debug, Eq, PartialEq, Clone)]\nstruct ConnectPacketPayload {\n    client_identifier: String,\n    will: Option<(TopicName, VarBytes)>,\n    user_name: Option<String>,\n    password: Option<String>,\n}\n\nimpl ConnectPacketPayload {\n    pub fn new(client_identifier: String) -> ConnectPacketPayload {\n        ConnectPacketPayload {\n            client_identifier,\n            will: None,\n            user_name: None,\n            password: None,\n        }\n    }\n}\n\nimpl Encodable for ConnectPacketPayload {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        self.client_identifier.encode(writer)?;\n\n        if let Some((will_topic, will_message)) = &self.will {\n            will_topic.encode(writer)?;\n            will_message.encode(writer)?;\n        }\n\n        if let Some(ref user_name) = self.user_name {\n            user_name.encode(writer)?;\n        }\n\n        if let Some(ref password) = self.password {\n            password.encode(writer)?;\n        }\n\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.client_identifier.encoded_length()\n            + self\n                .will\n                .as_ref()\n                .map(|(a, b)| a.encoded_length() + b.encoded_length())\n                .unwrap_or(0)\n            + self.user_name.as_ref().map(|t| t.encoded_length()).unwrap_or(0)\n            + self.password.as_ref().map(|t| t.encoded_length()).unwrap_or(0)\n    }\n}\n\nimpl Decodable for ConnectPacketPayload {\n    type Error = ConnectPacketError;\n    type Cond = Option<ConnectFlags>;\n\n    fn decode_with<R: Read>(\n        reader: &mut R,\n        rest: Option<ConnectFlags>,\n    ) -> Result<ConnectPacketPayload, ConnectPacketError> {\n        let mut need_will = false;\n        let mut need_user_name = false;\n        let mut need_password = false;\n\n        if let Some(r) = rest {\n            need_will = r.will_flag;\n            need_user_name = r.user_name;\n            need_password = r.password;\n        }\n\n        let ident = String::decode(reader)?;\n        let will = if need_will {\n            let topic = TopicName::decode(reader).map_err(|e| match e {\n                TopicNameDecodeError::IoError(e) => ConnectPacketError::from(e),\n                TopicNameDecodeError::InvalidTopicName(e) => e.into(),\n            })?;\n            let msg = VarBytes::decode(reader)?;\n            Some((topic, msg))\n        } else {\n            None\n        };\n        let uname = if need_user_name {\n            Some(String::decode(reader)?)\n        } else {\n            None\n        };\n        let pwd = if need_password {\n            Some(String::decode(reader)?)\n        } else {\n            None\n        };\n\n        Ok(ConnectPacketPayload {\n            client_identifier: ident,\n            will,\n            user_name: uname,\n            password: pwd,\n        })\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(transparent)]\npub enum ConnectPacketError {\n    IoError(#[from] io::Error),\n    TopicNameError(#[from] TopicNameError),\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use std::io::Cursor;\n\n    use crate::{Decodable, Encodable};\n\n    #[test]\n    fn test_connect_packet_encode_basic() {\n        let packet = ConnectPacket::new(\"12345\".to_owned());\n        let expected = b\"\\x10\\x11\\x00\\x04MQTT\\x04\\x00\\x00\\x00\\x00\\x0512345\";\n\n        let mut buf = Vec::new();\n        packet.encode(&mut buf).unwrap();\n\n        assert_eq!(&expected[..], &buf[..]);\n    }\n\n    #[test]\n    fn test_connect_packet_decode_basic() {\n        let encoded_data = b\"\\x10\\x11\\x00\\x04MQTT\\x04\\x00\\x00\\x00\\x00\\x0512345\";\n\n        let mut buf = Cursor::new(&encoded_data[..]);\n        let packet = ConnectPacket::decode(&mut buf).unwrap();\n\n        let expected = ConnectPacket::new(\"12345\".to_owned());\n        assert_eq!(expected, packet);\n    }\n\n    #[test]\n    fn test_connect_packet_user_name() {\n        let mut packet = ConnectPacket::new(\"12345\".to_owned());\n        packet.set_user_name(Some(\"mqtt_player\".to_owned()));\n\n        let mut buf = Vec::new();\n        packet.encode(&mut buf).unwrap();\n\n        let mut decode_buf = Cursor::new(buf);\n        let decoded_packet = ConnectPacket::decode(&mut decode_buf).unwrap();\n\n        assert_eq!(packet, decoded_packet);\n    }\n}\n"
  },
  {
    "path": "src/packet/disconnect.rs",
    "content": "//! DISCONNECT\n\nuse std::io::Read;\n\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\n\n/// `DISCONNECT` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct DisconnectPacket {\n    fixed_header: FixedHeader,\n}\n\nencodable_packet!(DisconnectPacket());\n\nimpl DisconnectPacket {\n    pub fn new() -> DisconnectPacket {\n        DisconnectPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::Disconnect), 0),\n        }\n    }\n}\n\nimpl Default for DisconnectPacket {\n    fn default() -> DisconnectPacket {\n        DisconnectPacket::new()\n    }\n}\n\nimpl DecodablePacket for DisconnectPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(_reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        Ok(DisconnectPacket { fixed_header })\n    }\n}\n"
  },
  {
    "path": "src/packet/mod.rs",
    "content": "//! Specific packets\n\nuse std::error::Error;\nuse std::fmt::{self, Debug};\nuse std::io::{self, Read, Write};\n\n#[cfg(feature = \"tokio\")]\nuse tokio::io::{AsyncRead, AsyncReadExt};\n\nuse crate::control::fixed_header::FixedHeaderError;\nuse crate::control::variable_header::VariableHeaderError;\nuse crate::control::ControlType;\nuse crate::control::FixedHeader;\nuse crate::topic_name::{TopicNameDecodeError, TopicNameError};\nuse crate::{Decodable, Encodable};\n\nmacro_rules! encodable_packet {\n    ($typ:ident($($field:ident),* $(,)?)) => {\n        impl $crate::packet::EncodablePacket for $typ {\n            fn fixed_header(&self) -> &$crate::control::fixed_header::FixedHeader {\n                &self.fixed_header\n            }\n\n            #[allow(unused)]\n            fn encode_packet<W: ::std::io::Write>(&self, writer: &mut W) -> ::std::io::Result<()> {\n                $($crate::encodable::Encodable::encode(&self.$field, writer)?;)*\n                Ok(())\n            }\n\n            fn encoded_packet_length(&self) -> u32 {\n                $($crate::encodable::Encodable::encoded_length(&self.$field) +)*\n                    0\n            }\n        }\n\n        impl $typ {\n            #[allow(unused)]\n            #[inline(always)]\n            fn fix_header_remaining_len(&mut self) {\n                self.fixed_header.remaining_length = $crate::packet::EncodablePacket::encoded_packet_length(self);\n            }\n        }\n    };\n}\n\npub use self::connack::ConnackPacket;\npub use self::connect::ConnectPacket;\npub use self::disconnect::DisconnectPacket;\npub use self::pingreq::PingreqPacket;\npub use self::pingresp::PingrespPacket;\npub use self::puback::PubackPacket;\npub use self::pubcomp::PubcompPacket;\npub use self::publish::{PublishPacket, PublishPacketRef};\npub use self::pubrec::PubrecPacket;\npub use self::pubrel::PubrelPacket;\npub use self::suback::SubackPacket;\npub use self::subscribe::SubscribePacket;\npub use self::unsuback::UnsubackPacket;\npub use self::unsubscribe::UnsubscribePacket;\n\npub use self::publish::QoSWithPacketIdentifier;\n\npub mod connack;\npub mod connect;\npub mod disconnect;\npub mod pingreq;\npub mod pingresp;\npub mod puback;\npub mod pubcomp;\npub mod publish;\npub mod pubrec;\npub mod pubrel;\npub mod suback;\npub mod subscribe;\npub mod unsuback;\npub mod unsubscribe;\n\n/// A trait representing a packet that can be encoded, when passed as `FooPacket` or as\n/// `&FooPacket`. Different from [`Encodable`] in that it prevents you from accidentally passing\n/// a type intended to be encoded only as a part of a packet and doesn't have a header, e.g.\n/// `Vec<u8>`.\npub trait EncodablePacket {\n    /// Get a reference to `FixedHeader`. All MQTT packet must have a fixed header.\n    fn fixed_header(&self) -> &FixedHeader;\n\n    /// Encodes packet data after fixed header, including variable headers and payload\n    fn encode_packet<W: Write>(&self, _writer: &mut W) -> io::Result<()> {\n        Ok(())\n    }\n\n    /// Length in bytes for data after fixed header, including variable headers and payload\n    fn encoded_packet_length(&self) -> u32 {\n        0\n    }\n}\n\nimpl<T: EncodablePacket> Encodable for T {\n    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {\n        self.fixed_header().encode(writer)?;\n        self.encode_packet(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.fixed_header().encoded_length() + self.encoded_packet_length()\n    }\n}\n\npub trait DecodablePacket: EncodablePacket + Sized {\n    type DecodePacketError: Error + 'static;\n\n    /// Decode packet given a `FixedHeader`\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>>;\n}\n\nimpl<T: DecodablePacket> Decodable for T {\n    type Error = PacketError<T>;\n    type Cond = Option<FixedHeader>;\n\n    fn decode_with<R: Read>(reader: &mut R, fixed_header: Self::Cond) -> Result<Self, Self::Error> {\n        let fixed_header: FixedHeader = if let Some(hdr) = fixed_header {\n            hdr\n        } else {\n            Decodable::decode(reader)?\n        };\n\n        <Self as DecodablePacket>::decode_packet(reader, fixed_header)\n    }\n}\n\n/// Parsing errors for packet\n#[derive(thiserror::Error)]\n#[error(transparent)]\npub enum PacketError<P>\nwhere\n    P: DecodablePacket,\n{\n    FixedHeaderError(#[from] FixedHeaderError),\n    VariableHeaderError(#[from] VariableHeaderError),\n    PayloadError(<P as DecodablePacket>::DecodePacketError),\n    IoError(#[from] io::Error),\n    TopicNameError(#[from] TopicNameError),\n}\n\nimpl<P> Debug for PacketError<P>\nwhere\n    P: DecodablePacket,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match *self {\n            PacketError::FixedHeaderError(ref e) => f.debug_tuple(\"FixedHeaderError\").field(e).finish(),\n            PacketError::VariableHeaderError(ref e) => f.debug_tuple(\"VariableHeaderError\").field(e).finish(),\n            PacketError::PayloadError(ref e) => f.debug_tuple(\"PayloadError\").field(e).finish(),\n            PacketError::IoError(ref e) => f.debug_tuple(\"IoError\").field(e).finish(),\n            PacketError::TopicNameError(ref e) => f.debug_tuple(\"TopicNameError\").field(e).finish(),\n        }\n    }\n}\n\nimpl<P: DecodablePacket> From<TopicNameDecodeError> for PacketError<P> {\n    fn from(e: TopicNameDecodeError) -> Self {\n        match e {\n            TopicNameDecodeError::IoError(e) => e.into(),\n            TopicNameDecodeError::InvalidTopicName(e) => e.into(),\n        }\n    }\n}\n\nmacro_rules! impl_variable_packet {\n    ($($name:ident & $errname:ident => $hdr:ident,)+) => {\n        /// Variable packet\n        #[derive(Debug, Eq, PartialEq, Clone)]\n        pub enum VariablePacket {\n            $(\n                $name($name),\n            )+\n        }\n\n        #[cfg(feature = \"tokio\")]\n        impl VariablePacket {\n            /// Asynchronously parse a packet from a `tokio::io::AsyncRead`\n            ///\n            /// This requires mqtt-rs to be built with `feature = \"tokio\"`\n            pub async fn parse<A: AsyncRead + Unpin>(rdr: &mut A) -> Result<Self, VariablePacketError> {\n                use std::io::Cursor;\n                let fixed_header = FixedHeader::parse(rdr).await?;\n\n                let mut buffer = vec![0u8; fixed_header.remaining_length as usize];\n                rdr.read_exact(&mut buffer).await?;\n\n                decode_with_header(&mut Cursor::new(buffer), fixed_header)\n            }\n        }\n\n        #[inline]\n        fn decode_with_header<R: io::Read>(rdr: &mut R, fixed_header: FixedHeader) -> Result<VariablePacket, VariablePacketError> {\n            match fixed_header.packet_type.control_type() {\n                $(\n                    ControlType::$hdr => {\n                        let pk = <$name as DecodablePacket>::decode_packet(rdr, fixed_header)?;\n                        Ok(VariablePacket::$name(pk))\n                    }\n                )+\n            }\n        }\n\n        $(\n            impl From<$name> for VariablePacket {\n                fn from(pk: $name) -> VariablePacket {\n                    VariablePacket::$name(pk)\n                }\n            }\n        )+\n\n        // impl Encodable for VariablePacket {\n        //     fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        //         match *self {\n        //             $(\n        //                 VariablePacket::$name(ref pk) => pk.encode(writer),\n        //             )+\n        //         }\n        //     }\n\n        //     fn encoded_length(&self) -> u32 {\n        //         match *self {\n        //             $(\n        //                 VariablePacket::$name(ref pk) => pk.encoded_length(),\n        //             )+\n        //         }\n        //     }\n        // }\n\n        impl EncodablePacket for VariablePacket {\n            fn fixed_header(&self) -> &FixedHeader {\n                match *self {\n                    $(\n                        VariablePacket::$name(ref pk) => pk.fixed_header(),\n                    )+\n                }\n            }\n\n            fn encode_packet<W: Write>(&self, writer: &mut W) -> io::Result<()> {\n                match *self {\n                    $(\n                        VariablePacket::$name(ref pk) => pk.encode_packet(writer),\n                    )+\n                }\n            }\n\n            fn encoded_packet_length(&self) -> u32 {\n                match *self {\n                    $(\n                        VariablePacket::$name(ref pk) => pk.encoded_packet_length(),\n                    )+\n                }\n            }\n        }\n\n        impl Decodable for VariablePacket {\n            type Error = VariablePacketError;\n            type Cond = Option<FixedHeader>;\n\n            fn decode_with<R: Read>(reader: &mut R, fixed_header: Self::Cond)\n                    -> Result<VariablePacket, Self::Error> {\n                let fixed_header = match fixed_header {\n                    Some(fh) => fh,\n                    None => {\n                        match FixedHeader::decode(reader) {\n                            Ok(header) => header,\n                            Err(FixedHeaderError::ReservedType(code, length)) => {\n                                let reader = &mut reader.take(length as u64);\n                                let mut buf = Vec::with_capacity(length as usize);\n                                reader.read_to_end(&mut buf)?;\n                                return Err(VariablePacketError::ReservedPacket(code, buf));\n                            },\n                            Err(err) => return Err(From::from(err))\n                        }\n                    }\n                };\n                let reader = &mut reader.take(fixed_header.remaining_length as u64);\n\n                decode_with_header(reader, fixed_header)\n            }\n        }\n\n        /// Parsing errors for variable packet\n        #[derive(Debug, thiserror::Error)]\n        pub enum VariablePacketError {\n            #[error(transparent)]\n            FixedHeaderError(#[from] FixedHeaderError),\n            #[error(\"reserved packet type ({0}), [u8, ..{}]\", .1.len())]\n            ReservedPacket(u8, Vec<u8>),\n            #[error(transparent)]\n            IoError(#[from] io::Error),\n            $(\n                #[error(transparent)]\n                $errname(#[from] PacketError<$name>),\n            )+\n        }\n    }\n}\n\nimpl_variable_packet! {\n    ConnectPacket       & ConnectPacketError        => Connect,\n    ConnackPacket       & ConnackPacketError        => ConnectAcknowledgement,\n\n    PublishPacket       & PublishPacketError        => Publish,\n    PubackPacket        & PubackPacketError         => PublishAcknowledgement,\n    PubrecPacket        & PubrecPacketError         => PublishReceived,\n    PubrelPacket        & PubrelPacketError         => PublishRelease,\n    PubcompPacket       & PubcompPacketError        => PublishComplete,\n\n    PingreqPacket       & PingreqPacketError        => PingRequest,\n    PingrespPacket      & PingrespPacketError       => PingResponse,\n\n    SubscribePacket     & SubscribePacketError      => Subscribe,\n    SubackPacket        & SubackPacketError         => SubscribeAcknowledgement,\n\n    UnsubscribePacket   & UnsubscribePacketError    => Unsubscribe,\n    UnsubackPacket      & UnsubackPacketError       => UnsubscribeAcknowledgement,\n\n    DisconnectPacket    & DisconnectPacketError     => Disconnect,\n}\n\nimpl VariablePacket {\n    pub fn new<T>(t: T) -> VariablePacket\n    where\n        VariablePacket: From<T>,\n    {\n        From::from(t)\n    }\n}\n\n#[cfg(feature = \"tokio-codec\")]\nmod tokio_codec {\n    use super::*;\n    use crate::control::packet_type::{PacketType, PacketTypeError};\n    use bytes::{Buf, BufMut, BytesMut};\n    use tokio_util::codec;\n\n    pub struct MqttDecoder {\n        state: DecodeState,\n    }\n\n    enum DecodeState {\n        Start,\n        Packet { length: u32, typ: DecodePacketType },\n    }\n\n    #[derive(Copy, Clone)]\n    enum DecodePacketType {\n        Standard(PacketType),\n        Reserved(u8),\n    }\n\n    impl MqttDecoder {\n        pub const fn new() -> Self {\n            MqttDecoder {\n                state: DecodeState::Start,\n            }\n        }\n    }\n\n    /// Like FixedHeader::decode(), but on a buffer instead of a stream. Returns None if it reaches\n    /// the end of the buffer before it finishes decoding the header.\n    #[inline]\n    fn decode_header(mut data: &[u8]) -> Option<Result<(DecodePacketType, u32, usize), FixedHeaderError>> {\n        let mut header_size = 0;\n        macro_rules! read_u8 {\n            () => {{\n                let (&x, rest) = data.split_first()?;\n                data = rest;\n                header_size += 1;\n                x\n            }};\n        }\n\n        let type_val = read_u8!();\n        let remaining_len = {\n            let mut cur = 0u32;\n            for i in 0.. {\n                let byte = read_u8!();\n                cur |= ((byte as u32) & 0x7F) << (7 * i);\n\n                if i >= 4 {\n                    return Some(Err(FixedHeaderError::MalformedRemainingLength));\n                }\n\n                if byte & 0x80 == 0 {\n                    break;\n                }\n            }\n\n            cur\n        };\n\n        let packet_type = match PacketType::from_u8(type_val) {\n            Ok(ty) => DecodePacketType::Standard(ty),\n            Err(PacketTypeError::ReservedType(ty, _)) => DecodePacketType::Reserved(ty),\n            Err(err) => return Some(Err(err.into())),\n        };\n        Some(Ok((packet_type, remaining_len, header_size)))\n    }\n\n    impl codec::Decoder for MqttDecoder {\n        type Item = VariablePacket;\n        type Error = VariablePacketError;\n        fn decode(&mut self, src: &mut BytesMut) -> Result<Option<VariablePacket>, VariablePacketError> {\n            loop {\n                match &mut self.state {\n                    DecodeState::Start => match decode_header(&src[..]) {\n                        Some(Ok((typ, length, header_size))) => {\n                            src.advance(header_size);\n                            self.state = DecodeState::Packet { length, typ };\n                            continue;\n                        }\n                        Some(Err(e)) => return Err(e.into()),\n                        None => return Ok(None),\n                    },\n                    DecodeState::Packet { length, typ } => {\n                        let length = *length;\n                        if src.remaining() < length as usize {\n                            return Ok(None);\n                        }\n                        let typ = *typ;\n\n                        self.state = DecodeState::Start;\n\n                        match typ {\n                            DecodePacketType::Standard(typ) => {\n                                let header = FixedHeader {\n                                    packet_type: typ,\n                                    remaining_length: length,\n                                };\n                                return decode_with_header(&mut src.reader(), header).map(Some);\n                            }\n                            DecodePacketType::Reserved(code) => {\n                                let data = src[..length as usize].to_vec();\n                                src.advance(length as usize);\n                                return Err(VariablePacketError::ReservedPacket(code, data));\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    pub struct MqttEncoder {\n        _priv: (),\n    }\n\n    impl MqttEncoder {\n        pub const fn new() -> Self {\n            MqttEncoder { _priv: () }\n        }\n    }\n\n    impl<T: EncodablePacket> codec::Encoder<T> for MqttEncoder {\n        type Error = io::Error;\n        fn encode(&mut self, packet: T, dst: &mut BytesMut) -> Result<(), io::Error> {\n            dst.reserve(packet.encoded_length() as usize);\n            packet.encode(&mut dst.writer())\n        }\n    }\n\n    pub struct MqttCodec {\n        decode: MqttDecoder,\n        encode: MqttEncoder,\n    }\n\n    impl MqttCodec {\n        pub const fn new() -> Self {\n            MqttCodec {\n                decode: MqttDecoder::new(),\n                encode: MqttEncoder::new(),\n            }\n        }\n    }\n\n    impl codec::Decoder for MqttCodec {\n        type Item = VariablePacket;\n        type Error = VariablePacketError;\n        #[inline]\n        fn decode(&mut self, src: &mut BytesMut) -> Result<Option<VariablePacket>, VariablePacketError> {\n            self.decode.decode(src)\n        }\n    }\n\n    impl<T: EncodablePacket> codec::Encoder<T> for MqttCodec {\n        type Error = io::Error;\n        #[inline]\n        fn encode(&mut self, packet: T, dst: &mut BytesMut) -> Result<(), io::Error> {\n            self.encode.encode(packet, dst)\n        }\n    }\n}\n\n#[cfg(feature = \"tokio-codec\")]\npub use tokio_codec::{MqttCodec, MqttDecoder, MqttEncoder};\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use std::io::Cursor;\n\n    use crate::{Decodable, Encodable};\n\n    #[test]\n    fn test_variable_packet_basic() {\n        let packet = ConnectPacket::new(\"1234\".to_owned());\n\n        // Wrap it\n        let var_packet = VariablePacket::new(packet);\n\n        // Encode\n        let mut buf = Vec::new();\n        var_packet.encode(&mut buf).unwrap();\n\n        // Decode\n        let mut decode_buf = Cursor::new(buf);\n        let decoded_packet = VariablePacket::decode(&mut decode_buf).unwrap();\n\n        assert_eq!(var_packet, decoded_packet);\n    }\n\n    #[cfg(feature = \"tokio\")]\n    #[tokio::test]\n    async fn test_variable_packet_async_parse() {\n        let packet = ConnectPacket::new(\"1234\".to_owned());\n\n        // Wrap it\n        let var_packet = VariablePacket::new(packet);\n\n        // Encode\n        let mut buf = Vec::new();\n        var_packet.encode(&mut buf).unwrap();\n\n        // Parse\n        let mut async_buf = buf.as_slice();\n        let decoded_packet = VariablePacket::parse(&mut async_buf).await.unwrap();\n\n        assert_eq!(var_packet, decoded_packet);\n    }\n\n    #[cfg(feature = \"tokio-codec\")]\n    #[tokio::test]\n    async fn test_variable_packet_framed() {\n        use crate::{QualityOfService, TopicFilter};\n        use futures::{SinkExt, StreamExt};\n        use tokio_util::codec::{FramedRead, FramedWrite};\n\n        let conn_packet = ConnectPacket::new(\"1234\".to_owned());\n        let sub_packet = SubscribePacket::new(1, vec![(TopicFilter::new(\"foo/#\").unwrap(), QualityOfService::Level0)]);\n\n        // small, to make sure buffering and stuff works\n        let (reader, writer) = tokio::io::duplex(8);\n\n        let task = tokio::spawn({\n            let (conn_packet, sub_packet) = (conn_packet.clone(), sub_packet.clone());\n            async move {\n                let mut sink = FramedWrite::new(writer, MqttEncoder::new());\n                sink.send(conn_packet).await.unwrap();\n                sink.send(sub_packet).await.unwrap();\n                SinkExt::<VariablePacket>::flush(&mut sink).await.unwrap();\n            }\n        });\n\n        let mut stream = FramedRead::new(reader, MqttDecoder::new());\n        let decoded_conn = stream.next().await.unwrap().unwrap();\n        let decoded_sub = stream.next().await.unwrap().unwrap();\n\n        task.await.unwrap();\n\n        assert!(stream.next().await.is_none());\n\n        assert_eq!(decoded_conn, conn_packet.into());\n        assert_eq!(decoded_sub, sub_packet.into());\n    }\n}\n"
  },
  {
    "path": "src/packet/pingreq.rs",
    "content": "//! PINGREQ\n\nuse std::io::Read;\n\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\n\n/// `PINGREQ` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PingreqPacket {\n    fixed_header: FixedHeader,\n}\n\nencodable_packet!(PingreqPacket());\n\nimpl PingreqPacket {\n    pub fn new() -> PingreqPacket {\n        PingreqPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PingRequest), 0),\n        }\n    }\n}\n\nimpl Default for PingreqPacket {\n    fn default() -> PingreqPacket {\n        PingreqPacket::new()\n    }\n}\n\nimpl DecodablePacket for PingreqPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(_reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        Ok(PingreqPacket { fixed_header })\n    }\n}\n"
  },
  {
    "path": "src/packet/pingresp.rs",
    "content": "//! PINGRESP\n\nuse std::io::Read;\n\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\n\n/// `PINGRESP` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PingrespPacket {\n    fixed_header: FixedHeader,\n}\n\nencodable_packet!(PingrespPacket());\n\nimpl PingrespPacket {\n    pub fn new() -> PingrespPacket {\n        PingrespPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PingResponse), 0),\n        }\n    }\n}\n\nimpl Default for PingrespPacket {\n    fn default() -> PingrespPacket {\n        PingrespPacket::new()\n    }\n}\n\nimpl DecodablePacket for PingrespPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(_reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        Ok(PingrespPacket { fixed_header })\n    }\n}\n"
  },
  {
    "path": "src/packet/puback.rs",
    "content": "//! PUBACK\n\nuse std::io::Read;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `PUBACK` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PubackPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n}\n\nencodable_packet!(PubackPacket(packet_identifier));\n\nimpl PubackPacket {\n    pub fn new(pkid: u16) -> PubackPacket {\n        PubackPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PublishAcknowledgement), 2),\n            packet_identifier: PacketIdentifier(pkid),\n        }\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n}\n\nimpl DecodablePacket for PubackPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        Ok(PubackPacket {\n            fixed_header,\n            packet_identifier,\n        })\n    }\n}\n"
  },
  {
    "path": "src/packet/pubcomp.rs",
    "content": "//! PUBCOMP\n\nuse std::io::Read;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `PUBCOMP` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PubcompPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n}\n\nencodable_packet!(PubcompPacket(packet_identifier));\n\nimpl PubcompPacket {\n    pub fn new(pkid: u16) -> PubcompPacket {\n        PubcompPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PublishComplete), 2),\n            packet_identifier: PacketIdentifier(pkid),\n        }\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n}\n\nimpl DecodablePacket for PubcompPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        Ok(PubcompPacket {\n            fixed_header,\n            packet_identifier,\n        })\n    }\n}\n"
  },
  {
    "path": "src/packet/publish.rs",
    "content": "//! PUBLISH\n\nuse std::io::{self, Read, Write};\n\nuse crate::control::{FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::qos::QualityOfService;\nuse crate::topic_name::TopicName;\nuse crate::{control::variable_header::PacketIdentifier, TopicNameRef};\nuse crate::{Decodable, Encodable};\n\nuse super::EncodablePacket;\n\n/// QoS with identifier pairs\n#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]\npub enum QoSWithPacketIdentifier {\n    Level0,\n    Level1(u16),\n    Level2(u16),\n}\n\nimpl QoSWithPacketIdentifier {\n    pub fn new(qos: QualityOfService, id: u16) -> QoSWithPacketIdentifier {\n        match (qos, id) {\n            (QualityOfService::Level0, _) => QoSWithPacketIdentifier::Level0,\n            (QualityOfService::Level1, id) => QoSWithPacketIdentifier::Level1(id),\n            (QualityOfService::Level2, id) => QoSWithPacketIdentifier::Level2(id),\n        }\n    }\n\n    pub fn split(self) -> (QualityOfService, Option<u16>) {\n        match self {\n            QoSWithPacketIdentifier::Level0 => (QualityOfService::Level0, None),\n            QoSWithPacketIdentifier::Level1(pkid) => (QualityOfService::Level1, Some(pkid)),\n            QoSWithPacketIdentifier::Level2(pkid) => (QualityOfService::Level2, Some(pkid)),\n        }\n    }\n}\n\n/// `PUBLISH` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PublishPacket {\n    fixed_header: FixedHeader,\n    topic_name: TopicName,\n    packet_identifier: Option<PacketIdentifier>,\n    payload: Vec<u8>,\n}\n\nencodable_packet!(PublishPacket(topic_name, packet_identifier, payload));\n\nimpl PublishPacket {\n    pub fn new<P: Into<Vec<u8>>>(topic_name: TopicName, qos: QoSWithPacketIdentifier, payload: P) -> PublishPacket {\n        let (qos, pkid) = qos.split();\n        let mut pk = PublishPacket {\n            fixed_header: FixedHeader::new(PacketType::publish(qos), 0),\n            topic_name,\n            packet_identifier: pkid.map(PacketIdentifier),\n            payload: payload.into(),\n        };\n        pk.fix_header_remaining_len();\n        pk\n    }\n\n    pub fn set_dup(&mut self, dup: bool) {\n        self.fixed_header\n            .packet_type\n            .update_flags(|flags| (flags & !(1 << 3)) | (dup as u8) << 3)\n    }\n\n    pub fn dup(&self) -> bool {\n        self.fixed_header.packet_type.flags() & 0x80 != 0\n    }\n\n    pub fn set_qos(&mut self, qos: QoSWithPacketIdentifier) {\n        let (qos, pkid) = qos.split();\n        self.fixed_header\n            .packet_type\n            .update_flags(|flags| (flags & !0b0110) | (qos as u8) << 1);\n        self.packet_identifier = pkid.map(PacketIdentifier);\n        self.fix_header_remaining_len();\n    }\n\n    pub fn qos(&self) -> QoSWithPacketIdentifier {\n        match self.packet_identifier {\n            None => QoSWithPacketIdentifier::Level0,\n            Some(pkid) => {\n                let qos_val = (self.fixed_header.packet_type.flags() & 0b0110) >> 1;\n                match qos_val {\n                    1 => QoSWithPacketIdentifier::Level1(pkid.0),\n                    2 => QoSWithPacketIdentifier::Level2(pkid.0),\n                    _ => unreachable!(),\n                }\n            }\n        }\n    }\n\n    pub fn set_retain(&mut self, ret: bool) {\n        self.fixed_header\n            .packet_type\n            .update_flags(|flags| (flags & !0b0001) | (ret as u8))\n    }\n\n    pub fn retain(&self) -> bool {\n        self.fixed_header.packet_type.flags() & 0b0001 != 0\n    }\n\n    pub fn set_topic_name(&mut self, topic_name: TopicName) {\n        self.topic_name = topic_name;\n        self.fix_header_remaining_len();\n    }\n\n    pub fn topic_name(&self) -> &str {\n        &self.topic_name[..]\n    }\n\n    pub fn payload(&self) -> &[u8] {\n        &self.payload\n    }\n\n    pub fn set_payload<P: Into<Vec<u8>>>(&mut self, payload: P) {\n        self.payload = payload.into();\n        self.fix_header_remaining_len();\n    }\n}\n\nimpl DecodablePacket for PublishPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let topic_name = TopicName::decode(reader)?;\n\n        let qos = (fixed_header.packet_type.flags() & 0b0110) >> 1;\n        let packet_identifier = if qos > 0 {\n            Some(PacketIdentifier::decode(reader)?)\n        } else {\n            None\n        };\n\n        let vhead_len =\n            topic_name.encoded_length() + packet_identifier.as_ref().map(|x| x.encoded_length()).unwrap_or(0);\n        let payload_len = fixed_header.remaining_length - vhead_len;\n\n        let payload = Vec::<u8>::decode_with(reader, Some(payload_len))?;\n\n        Ok(PublishPacket {\n            fixed_header,\n            topic_name,\n            packet_identifier,\n            payload,\n        })\n    }\n}\n\n/// `PUBLISH` packet by reference, for encoding only\npub struct PublishPacketRef<'a> {\n    fixed_header: FixedHeader,\n    topic_name: &'a TopicNameRef,\n    packet_identifier: Option<PacketIdentifier>,\n    payload: &'a [u8],\n}\n\nimpl<'a> PublishPacketRef<'a> {\n    pub fn new(topic_name: &'a TopicNameRef, qos: QoSWithPacketIdentifier, payload: &'a [u8]) -> PublishPacketRef<'a> {\n        let (qos, pkid) = qos.split();\n\n        let mut pk = PublishPacketRef {\n            fixed_header: FixedHeader::new(PacketType::publish(qos), 0),\n            topic_name,\n            packet_identifier: pkid.map(PacketIdentifier),\n            payload,\n        };\n        pk.fix_header_remaining_len();\n        pk\n    }\n\n    fn fix_header_remaining_len(&mut self) {\n        self.fixed_header.remaining_length =\n            self.topic_name.encoded_length() + self.packet_identifier.encoded_length() + self.payload.encoded_length();\n    }\n}\n\nimpl EncodablePacket for PublishPacketRef<'_> {\n    fn fixed_header(&self) -> &FixedHeader {\n        &self.fixed_header\n    }\n\n    fn encode_packet<W: Write>(&self, writer: &mut W) -> io::Result<()> {\n        self.topic_name.encode(writer)?;\n        self.packet_identifier.encode(writer)?;\n        self.payload.encode(writer)\n    }\n\n    fn encoded_packet_length(&self) -> u32 {\n        self.topic_name.encoded_length() + self.packet_identifier.encoded_length() + self.payload.encoded_length()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    use std::io::Cursor;\n\n    use crate::topic_name::TopicName;\n    use crate::{Decodable, Encodable};\n\n    #[test]\n    fn test_publish_packet_basic() {\n        let packet = PublishPacket::new(\n            TopicName::new(\"a/b\".to_owned()).unwrap(),\n            QoSWithPacketIdentifier::Level2(10),\n            b\"Hello world!\".to_vec(),\n        );\n\n        let mut buf = Vec::new();\n        packet.encode(&mut buf).unwrap();\n\n        let mut decode_buf = Cursor::new(buf);\n        let decoded = PublishPacket::decode(&mut decode_buf).unwrap();\n\n        assert_eq!(packet, decoded);\n    }\n\n    #[test]\n    fn issue56() {\n        let mut packet = PublishPacket::new(\n            TopicName::new(\"topic\").unwrap(),\n            QoSWithPacketIdentifier::Level0,\n            Vec::new(),\n        );\n        assert_eq!(packet.fixed_header().remaining_length, 7);\n\n        packet.set_qos(QoSWithPacketIdentifier::Level1(1));\n        assert_eq!(packet.fixed_header().remaining_length, 9);\n    }\n}\n"
  },
  {
    "path": "src/packet/pubrec.rs",
    "content": "//! PUBREC\n\nuse std::io::Read;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `PUBREC` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PubrecPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n}\n\nencodable_packet!(PubrecPacket(packet_identifier));\n\nimpl PubrecPacket {\n    pub fn new(pkid: u16) -> PubrecPacket {\n        PubrecPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PublishReceived), 2),\n            packet_identifier: PacketIdentifier(pkid),\n        }\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n}\n\nimpl DecodablePacket for PubrecPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        Ok(PubrecPacket {\n            fixed_header,\n            packet_identifier,\n        })\n    }\n}\n"
  },
  {
    "path": "src/packet/pubrel.rs",
    "content": "//! PUBREL\n\nuse std::io::Read;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `PUBREL` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct PubrelPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n}\n\nencodable_packet!(PubrelPacket(packet_identifier));\n\nimpl PubrelPacket {\n    pub fn new(pkid: u16) -> PubrelPacket {\n        PubrelPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::PublishRelease), 2),\n            packet_identifier: PacketIdentifier(pkid),\n        }\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n}\n\nimpl DecodablePacket for PubrelPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        Ok(PubrelPacket {\n            fixed_header,\n            packet_identifier,\n        })\n    }\n}\n"
  },
  {
    "path": "src/packet/suback.rs",
    "content": "//! SUBACK\n\nuse std::cmp::Ordering;\n\nuse std::io::{self, Read, Write};\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::qos::QualityOfService;\nuse crate::{Decodable, Encodable};\n\n/// Subscribe code\n#[repr(u8)]\n#[derive(Debug, Eq, PartialEq, Copy, Clone)]\npub enum SubscribeReturnCode {\n    MaximumQoSLevel0 = 0x00,\n    MaximumQoSLevel1 = 0x01,\n    MaximumQoSLevel2 = 0x02,\n    Failure = 0x80,\n}\n\nimpl PartialOrd for SubscribeReturnCode {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        use self::SubscribeReturnCode::*;\n        match (self, other) {\n            (&Failure, _) => None,\n            (_, &Failure) => None,\n            (&MaximumQoSLevel0, &MaximumQoSLevel0) => Some(Ordering::Equal),\n            (&MaximumQoSLevel1, &MaximumQoSLevel1) => Some(Ordering::Equal),\n            (&MaximumQoSLevel2, &MaximumQoSLevel2) => Some(Ordering::Equal),\n            (&MaximumQoSLevel0, _) => Some(Ordering::Less),\n            (&MaximumQoSLevel1, &MaximumQoSLevel0) => Some(Ordering::Greater),\n            (&MaximumQoSLevel1, &MaximumQoSLevel2) => Some(Ordering::Less),\n            (&MaximumQoSLevel2, _) => Some(Ordering::Greater),\n        }\n    }\n}\n\nimpl From<QualityOfService> for SubscribeReturnCode {\n    fn from(qos: QualityOfService) -> Self {\n        match qos {\n            QualityOfService::Level0 => SubscribeReturnCode::MaximumQoSLevel0,\n            QualityOfService::Level1 => SubscribeReturnCode::MaximumQoSLevel1,\n            QualityOfService::Level2 => SubscribeReturnCode::MaximumQoSLevel2,\n        }\n    }\n}\n\n/// `SUBACK` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct SubackPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n    payload: SubackPacketPayload,\n}\n\nencodable_packet!(SubackPacket(packet_identifier, payload));\n\nimpl SubackPacket {\n    pub fn new(pkid: u16, subscribes: Vec<SubscribeReturnCode>) -> SubackPacket {\n        let mut pk = SubackPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::SubscribeAcknowledgement), 0),\n            packet_identifier: PacketIdentifier(pkid),\n            payload: SubackPacketPayload::new(subscribes),\n        };\n        pk.fix_header_remaining_len();\n        pk\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n\n    pub fn subscribes(&self) -> &[SubscribeReturnCode] {\n        &self.payload.subscribes[..]\n    }\n}\n\nimpl DecodablePacket for SubackPacket {\n    type DecodePacketError = SubackPacketError;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier = PacketIdentifier::decode(reader)?;\n        let payload: SubackPacketPayload = SubackPacketPayload::decode_with(\n            reader,\n            fixed_header.remaining_length - packet_identifier.encoded_length(),\n        )\n        .map_err(PacketError::PayloadError)?;\n        Ok(SubackPacket {\n            fixed_header,\n            packet_identifier,\n            payload,\n        })\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\nstruct SubackPacketPayload {\n    subscribes: Vec<SubscribeReturnCode>,\n}\n\nimpl SubackPacketPayload {\n    pub fn new(subs: Vec<SubscribeReturnCode>) -> SubackPacketPayload {\n        SubackPacketPayload { subscribes: subs }\n    }\n}\n\nimpl Encodable for SubackPacketPayload {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        for code in self.subscribes.iter() {\n            writer.write_u8(*code as u8)?;\n        }\n\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.subscribes.len() as u32\n    }\n}\n\nimpl Decodable for SubackPacketPayload {\n    type Error = SubackPacketError;\n    type Cond = u32;\n\n    fn decode_with<R: Read>(reader: &mut R, payload_len: u32) -> Result<SubackPacketPayload, SubackPacketError> {\n        let mut subs = Vec::new();\n\n        for _ in 0..payload_len {\n            let retcode = match reader.read_u8()? {\n                0x00 => SubscribeReturnCode::MaximumQoSLevel0,\n                0x01 => SubscribeReturnCode::MaximumQoSLevel1,\n                0x02 => SubscribeReturnCode::MaximumQoSLevel2,\n                0x80 => SubscribeReturnCode::Failure,\n                code => return Err(SubackPacketError::InvalidSubscribeReturnCode(code)),\n            };\n\n            subs.push(retcode);\n        }\n\n        Ok(SubackPacketPayload::new(subs))\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum SubackPacketError {\n    #[error(transparent)]\n    IoError(#[from] io::Error),\n    #[error(\"invalid subscribe return code {0}\")]\n    InvalidSubscribeReturnCode(u8),\n}\n"
  },
  {
    "path": "src/packet/subscribe.rs",
    "content": "//! SUBSCRIBE\n\nuse std::io::{self, Read, Write};\nuse std::string::FromUtf8Error;\n\nuse byteorder::{ReadBytesExt, WriteBytesExt};\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::topic_filter::{TopicFilter, TopicFilterDecodeError, TopicFilterError};\nuse crate::{Decodable, Encodable, QualityOfService};\n\n/// `SUBSCRIBE` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct SubscribePacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n    payload: SubscribePacketPayload,\n}\n\nencodable_packet!(SubscribePacket(packet_identifier, payload));\n\nimpl SubscribePacket {\n    pub fn new(pkid: u16, subscribes: Vec<(TopicFilter, QualityOfService)>) -> SubscribePacket {\n        let mut pk = SubscribePacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::Subscribe), 0),\n            packet_identifier: PacketIdentifier(pkid),\n            payload: SubscribePacketPayload::new(subscribes),\n        };\n        pk.fix_header_remaining_len();\n        pk\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n\n    pub fn subscribes(&self) -> &[(TopicFilter, QualityOfService)] {\n        &self.payload.subscribes[..]\n    }\n}\n\nimpl DecodablePacket for SubscribePacket {\n    type DecodePacketError = SubscribePacketError;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        let payload: SubscribePacketPayload = SubscribePacketPayload::decode_with(\n            reader,\n            fixed_header.remaining_length - packet_identifier.encoded_length(),\n        )\n        .map_err(PacketError::PayloadError)?;\n        Ok(SubscribePacket {\n            fixed_header,\n            packet_identifier,\n            payload,\n        })\n    }\n}\n\n/// Payload of subscribe packet\n#[derive(Debug, Eq, PartialEq, Clone)]\nstruct SubscribePacketPayload {\n    subscribes: Vec<(TopicFilter, QualityOfService)>,\n}\n\nimpl SubscribePacketPayload {\n    pub fn new(subs: Vec<(TopicFilter, QualityOfService)>) -> SubscribePacketPayload {\n        SubscribePacketPayload { subscribes: subs }\n    }\n}\n\nimpl Encodable for SubscribePacketPayload {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        for &(ref filter, ref qos) in self.subscribes.iter() {\n            filter.encode(writer)?;\n            writer.write_u8(*qos as u8)?;\n        }\n\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.subscribes.iter().fold(0, |b, a| b + a.0.encoded_length() + 1)\n    }\n}\n\nimpl Decodable for SubscribePacketPayload {\n    type Error = SubscribePacketError;\n    type Cond = u32;\n\n    fn decode_with<R: Read>(\n        reader: &mut R,\n        mut payload_len: u32,\n    ) -> Result<SubscribePacketPayload, SubscribePacketError> {\n        let mut subs = Vec::new();\n\n        while payload_len > 0 {\n            let filter = TopicFilter::decode(reader)?;\n            let qos = match reader.read_u8()? {\n                0 => QualityOfService::Level0,\n                1 => QualityOfService::Level1,\n                2 => QualityOfService::Level2,\n                _ => return Err(SubscribePacketError::InvalidQualityOfService),\n            };\n\n            payload_len -= filter.encoded_length() + 1;\n            subs.push((filter, qos));\n        }\n\n        Ok(SubscribePacketPayload::new(subs))\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum SubscribePacketError {\n    #[error(transparent)]\n    IoError(#[from] io::Error),\n    #[error(transparent)]\n    FromUtf8Error(#[from] FromUtf8Error),\n    #[error(\"invalid quality of service\")]\n    InvalidQualityOfService,\n    #[error(transparent)]\n    TopicFilterError(#[from] TopicFilterError),\n}\n\nimpl From<TopicFilterDecodeError> for SubscribePacketError {\n    fn from(e: TopicFilterDecodeError) -> Self {\n        match e {\n            TopicFilterDecodeError::IoError(e) => e.into(),\n            TopicFilterDecodeError::InvalidTopicFilter(e) => e.into(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/packet/unsuback.rs",
    "content": "//! UNSUBACK\n\nuse std::io::Read;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::Decodable;\n\n/// `UNSUBACK` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct UnsubackPacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n}\n\nencodable_packet!(UnsubackPacket(packet_identifier));\n\nimpl UnsubackPacket {\n    pub fn new(pkid: u16) -> UnsubackPacket {\n        UnsubackPacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::UnsubscribeAcknowledgement), 2),\n            packet_identifier: PacketIdentifier(pkid),\n        }\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n}\n\nimpl DecodablePacket for UnsubackPacket {\n    type DecodePacketError = std::convert::Infallible;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        Ok(UnsubackPacket {\n            fixed_header,\n            packet_identifier,\n        })\n    }\n}\n"
  },
  {
    "path": "src/packet/unsubscribe.rs",
    "content": "//! UNSUBSCRIBE\n\nuse std::io::{self, Read, Write};\nuse std::string::FromUtf8Error;\n\nuse crate::control::variable_header::PacketIdentifier;\nuse crate::control::{ControlType, FixedHeader, PacketType};\nuse crate::packet::{DecodablePacket, PacketError};\nuse crate::topic_filter::{TopicFilter, TopicFilterDecodeError, TopicFilterError};\nuse crate::{Decodable, Encodable};\n\n/// `UNSUBSCRIBE` packet\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct UnsubscribePacket {\n    fixed_header: FixedHeader,\n    packet_identifier: PacketIdentifier,\n    payload: UnsubscribePacketPayload,\n}\n\nencodable_packet!(UnsubscribePacket(packet_identifier, payload));\n\nimpl UnsubscribePacket {\n    pub fn new(pkid: u16, subscribes: Vec<TopicFilter>) -> UnsubscribePacket {\n        let mut pk = UnsubscribePacket {\n            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::Unsubscribe), 0),\n            packet_identifier: PacketIdentifier(pkid),\n            payload: UnsubscribePacketPayload::new(subscribes),\n        };\n        pk.fix_header_remaining_len();\n        pk\n    }\n\n    pub fn packet_identifier(&self) -> u16 {\n        self.packet_identifier.0\n    }\n\n    pub fn set_packet_identifier(&mut self, pkid: u16) {\n        self.packet_identifier.0 = pkid;\n    }\n\n    pub fn subscribes(&self) -> &[TopicFilter] {\n        &self.payload.subscribes[..]\n    }\n}\n\nimpl DecodablePacket for UnsubscribePacket {\n    type DecodePacketError = UnsubscribePacketError;\n\n    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {\n        let packet_identifier: PacketIdentifier = PacketIdentifier::decode(reader)?;\n        let payload: UnsubscribePacketPayload = UnsubscribePacketPayload::decode_with(\n            reader,\n            fixed_header.remaining_length - packet_identifier.encoded_length(),\n        )\n        .map_err(PacketError::PayloadError)?;\n        Ok(UnsubscribePacket {\n            fixed_header,\n            packet_identifier,\n            payload,\n        })\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone)]\nstruct UnsubscribePacketPayload {\n    subscribes: Vec<TopicFilter>,\n}\n\nimpl UnsubscribePacketPayload {\n    pub fn new(subs: Vec<TopicFilter>) -> UnsubscribePacketPayload {\n        UnsubscribePacketPayload { subscribes: subs }\n    }\n}\n\nimpl Encodable for UnsubscribePacketPayload {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        for filter in self.subscribes.iter() {\n            filter.encode(writer)?;\n        }\n\n        Ok(())\n    }\n\n    fn encoded_length(&self) -> u32 {\n        self.subscribes.iter().fold(0, |b, a| b + a.encoded_length())\n    }\n}\n\nimpl Decodable for UnsubscribePacketPayload {\n    type Error = UnsubscribePacketError;\n    type Cond = u32;\n\n    fn decode_with<R: Read>(\n        reader: &mut R,\n        mut payload_len: u32,\n    ) -> Result<UnsubscribePacketPayload, UnsubscribePacketError> {\n        let mut subs = Vec::new();\n\n        while payload_len > 0 {\n            let filter = TopicFilter::decode(reader)?;\n            payload_len -= filter.encoded_length();\n            subs.push(filter);\n        }\n\n        Ok(UnsubscribePacketPayload::new(subs))\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(transparent)]\npub enum UnsubscribePacketError {\n    IoError(#[from] io::Error),\n    FromUtf8Error(#[from] FromUtf8Error),\n    TopicFilterError(#[from] TopicFilterError),\n}\n\nimpl From<TopicFilterDecodeError> for UnsubscribePacketError {\n    fn from(e: TopicFilterDecodeError) -> Self {\n        match e {\n            TopicFilterDecodeError::IoError(e) => e.into(),\n            TopicFilterDecodeError::InvalidTopicFilter(e) => e.into(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/qos.rs",
    "content": "//! QoS (Quality of Services)\n\nuse crate::packet::publish::QoSWithPacketIdentifier;\n\n#[repr(u8)]\n#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]\npub enum QualityOfService {\n    Level0 = 0,\n    Level1 = 1,\n    Level2 = 2,\n}\n\nimpl From<QoSWithPacketIdentifier> for QualityOfService {\n    fn from(qos: QoSWithPacketIdentifier) -> Self {\n        match qos {\n            QoSWithPacketIdentifier::Level0 => QualityOfService::Level0,\n            QoSWithPacketIdentifier::Level1(_) => QualityOfService::Level1,\n            QoSWithPacketIdentifier::Level2(_) => QualityOfService::Level2,\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use std::cmp::min;\n\n    #[test]\n    fn min_qos() {\n        let q1 = QoSWithPacketIdentifier::Level1(0).into();\n        let q2 = QualityOfService::Level2;\n        assert_eq!(min(q1, q2), q1);\n\n        let q1 = QoSWithPacketIdentifier::Level0.into();\n        let q2 = QualityOfService::Level2;\n        assert_eq!(min(q1, q2), q1);\n\n        let q1 = QoSWithPacketIdentifier::Level2(0).into();\n        let q2 = QualityOfService::Level1;\n        assert_eq!(min(q1, q2), q2);\n    }\n}\n"
  },
  {
    "path": "src/topic_filter.rs",
    "content": "//! Topic filter\n\nuse std::io::{self, Read, Write};\nuse std::ops::Deref;\n\nuse crate::topic_name::TopicNameRef;\nuse crate::{Decodable, Encodable};\n\n#[inline]\nfn is_invalid_topic_filter(topic: &str) -> bool {\n    if topic.is_empty() || topic.as_bytes().len() > 65535 {\n        return true;\n    }\n\n    let mut found_hash = false;\n    for member in topic.split('/') {\n        if found_hash {\n            return true;\n        }\n\n        match member {\n            \"#\" => found_hash = true,\n            \"+\" => {}\n            _ => {\n                if member.contains(['#', '+']) {\n                    return true;\n                }\n            }\n        }\n    }\n\n    false\n}\n\n/// Topic filter\n///\n/// <http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106>\n///\n/// ```rust\n/// use mqtt::{TopicFilter, TopicNameRef};\n///\n/// let topic_filter = TopicFilter::new(\"sport/+/player1\").unwrap();\n/// let matcher = topic_filter.get_matcher();\n/// assert!(matcher.is_match(TopicNameRef::new(\"sport/abc/player1\").unwrap()));\n/// ```\n#[derive(Debug, Eq, PartialEq, Clone, Hash, Ord, PartialOrd)]\npub struct TopicFilter(String);\n\nimpl TopicFilter {\n    /// Creates a new topic filter from string\n    /// Return error if it is not a valid topic filter\n    pub fn new<S: Into<String>>(topic: S) -> Result<TopicFilter, TopicFilterError> {\n        let topic = topic.into();\n        if is_invalid_topic_filter(&topic) {\n            Err(TopicFilterError(topic))\n        } else {\n            Ok(TopicFilter(topic))\n        }\n    }\n\n    /// Creates a new topic filter from string without validation\n    ///\n    /// # Safety\n    ///\n    /// Topic filters' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).\n    /// Creating a filter from raw string may cause errors\n    pub unsafe fn new_unchecked<S: Into<String>>(topic: S) -> TopicFilter {\n        TopicFilter(topic.into())\n    }\n}\n\nimpl From<TopicFilter> for String {\n    fn from(topic: TopicFilter) -> String {\n        topic.0\n    }\n}\n\nimpl Encodable for TopicFilter {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self.0[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self.0[..]).encoded_length()\n    }\n}\n\nimpl Decodable for TopicFilter {\n    type Error = TopicFilterDecodeError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<TopicFilter, TopicFilterDecodeError> {\n        let topic_filter = String::decode(reader)?;\n        Ok(TopicFilter::new(topic_filter)?)\n    }\n}\n\nimpl Deref for TopicFilter {\n    type Target = TopicFilterRef;\n\n    fn deref(&self) -> &TopicFilterRef {\n        unsafe { TopicFilterRef::new_unchecked(&self.0) }\n    }\n}\n\n/// Reference to a `TopicFilter`\n#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]\n#[repr(transparent)]\npub struct TopicFilterRef(str);\n\nimpl TopicFilterRef {\n    /// Creates a new topic filter from string\n    /// Return error if it is not a valid topic filter\n    pub fn new<S: AsRef<str> + ?Sized>(topic: &S) -> Result<&TopicFilterRef, TopicFilterError> {\n        let topic = topic.as_ref();\n        if is_invalid_topic_filter(topic) {\n            Err(TopicFilterError(topic.to_owned()))\n        } else {\n            Ok(unsafe { &*(topic as *const str as *const TopicFilterRef) })\n        }\n    }\n\n    /// Creates a new topic filter from string without validation\n    ///\n    /// # Safety\n    ///\n    /// Topic filters' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).\n    /// Creating a filter from raw string may cause errors\n    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic: &S) -> &TopicFilterRef {\n        let topic = topic.as_ref();\n        &*(topic as *const str as *const TopicFilterRef)\n    }\n\n    /// Get a matcher\n    pub fn get_matcher(&self) -> TopicFilterMatcher<'_> {\n        TopicFilterMatcher::new(&self.0)\n    }\n}\n\nimpl Deref for TopicFilterRef {\n    type Target = str;\n\n    fn deref(&self) -> &str {\n        &self.0\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"invalid topic filter ({0})\")]\npub struct TopicFilterError(pub String);\n\n/// Errors while parsing topic filters\n#[derive(Debug, thiserror::Error)]\n#[error(transparent)]\npub enum TopicFilterDecodeError {\n    IoError(#[from] io::Error),\n    InvalidTopicFilter(#[from] TopicFilterError),\n}\n\n/// Matcher for matching topic names with this filter\n#[derive(Debug, Copy, Clone)]\npub struct TopicFilterMatcher<'a> {\n    topic_filter: &'a str,\n}\n\nimpl<'a> TopicFilterMatcher<'a> {\n    fn new(filter: &'a str) -> TopicFilterMatcher<'a> {\n        TopicFilterMatcher { topic_filter: filter }\n    }\n\n    /// Check if this filter can match the `topic_name`\n    pub fn is_match(&self, topic_name: &TopicNameRef) -> bool {\n        let mut tn_itr = topic_name.split('/');\n        let mut ft_itr = self.topic_filter.split('/');\n\n        // The Server MUST NOT match Topic Filters starting with a wildcard character (# or +)\n        // with Topic Names beginning with a $ character [MQTT-4.7.2-1].\n\n        let first_ft = ft_itr.next().unwrap();\n        let first_tn = tn_itr.next().unwrap();\n\n        if first_tn.starts_with('$') {\n            if first_tn != first_ft {\n                return false;\n            }\n        } else {\n            match first_ft {\n                // Matches the whole topic\n                \"#\" => return true,\n                \"+\" => {}\n                _ => {\n                    if first_tn != first_ft {\n                        return false;\n                    }\n                }\n            }\n        }\n\n        loop {\n            match (ft_itr.next(), tn_itr.next()) {\n                (Some(ft), Some(tn)) => match ft {\n                    \"#\" => break,\n                    \"+\" => {}\n                    _ => {\n                        if ft != tn {\n                            return false;\n                        }\n                    }\n                },\n                (Some(ft), None) => {\n                    if ft != \"#\" {\n                        return false;\n                    } else {\n                        break;\n                    }\n                }\n                (None, Some(..)) => return false,\n                (None, None) => break,\n            }\n        }\n\n        true\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn topic_filter_validate() {\n        let topic = \"#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport/tennis/player1\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport/tennis/player1/ranking\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport/tennis/player1/#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport/tennis/#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport/tennis#\".to_owned();\n        assert!(TopicFilter::new(topic).is_err());\n\n        let topic = \"sport/tennis/#/ranking\".to_owned();\n        assert!(TopicFilter::new(topic).is_err());\n\n        let topic = \"+\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"+/tennis/#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"sport+\".to_owned();\n        assert!(TopicFilter::new(topic).is_err());\n\n        let topic = \"sport/+/player1\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"+/+\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"$SYS/#\".to_owned();\n        TopicFilter::new(topic).unwrap();\n\n        let topic = \"$SYS\".to_owned();\n        TopicFilter::new(topic).unwrap();\n    }\n\n    #[test]\n    fn topic_filter_matcher() {\n        let filter = TopicFilter::new(\"sport/#\").unwrap();\n        let matcher = filter.get_matcher();\n        assert!(matcher.is_match(TopicNameRef::new(\"sport\").unwrap()));\n\n        let filter = TopicFilter::new(\"#\").unwrap();\n        let matcher = filter.get_matcher();\n        assert!(matcher.is_match(TopicNameRef::new(\"sport\").unwrap()));\n        assert!(matcher.is_match(TopicNameRef::new(\"/\").unwrap()));\n        assert!(matcher.is_match(TopicNameRef::new(\"abc/def\").unwrap()));\n        assert!(!matcher.is_match(TopicNameRef::new(\"$SYS\").unwrap()));\n        assert!(!matcher.is_match(TopicNameRef::new(\"$SYS/abc\").unwrap()));\n\n        let filter = TopicFilter::new(\"+/monitor/Clients\").unwrap();\n        let matcher = filter.get_matcher();\n        assert!(!matcher.is_match(TopicNameRef::new(\"$SYS/monitor/Clients\").unwrap()));\n\n        let filter = TopicFilter::new(\"$SYS/#\").unwrap();\n        let matcher = filter.get_matcher();\n        assert!(matcher.is_match(TopicNameRef::new(\"$SYS/monitor/Clients\").unwrap()));\n        assert!(matcher.is_match(TopicNameRef::new(\"$SYS\").unwrap()));\n\n        let filter = TopicFilter::new(\"$SYS/monitor/+\").unwrap();\n        let matcher = filter.get_matcher();\n        assert!(matcher.is_match(TopicNameRef::new(\"$SYS/monitor/Clients\").unwrap()));\n    }\n}\n"
  },
  {
    "path": "src/topic_name.rs",
    "content": "//! Topic name\n\nuse std::{\n    borrow::{Borrow, BorrowMut},\n    io::{self, Read, Write},\n    ops::{Deref, DerefMut},\n};\n\nuse crate::{Decodable, Encodable};\n\n#[inline]\nfn is_invalid_topic_name(topic_name: &str) -> bool {\n    topic_name.is_empty() || topic_name.as_bytes().len() > 65535 || topic_name.chars().any(|ch| ch == '#' || ch == '+')\n}\n\n/// Topic name\n///\n/// <http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106>\n#[derive(Debug, Eq, PartialEq, Clone, Hash, Ord, PartialOrd)]\npub struct TopicName(String);\n\nimpl TopicName {\n    /// Creates a new topic name from string\n    /// Return error if the string is not a valid topic name\n    pub fn new<S: Into<String>>(topic_name: S) -> Result<TopicName, TopicNameError> {\n        let topic_name = topic_name.into();\n        if is_invalid_topic_name(&topic_name) {\n            Err(TopicNameError(topic_name))\n        } else {\n            Ok(TopicName(topic_name))\n        }\n    }\n\n    /// Creates a new topic name from string without validation\n    ///\n    /// # Safety\n    ///\n    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).\n    /// Creating a name from raw string may cause errors\n    pub unsafe fn new_unchecked(topic_name: String) -> TopicName {\n        TopicName(topic_name)\n    }\n}\n\nimpl From<TopicName> for String {\n    fn from(topic_name: TopicName) -> String {\n        topic_name.0\n    }\n}\n\nimpl Deref for TopicName {\n    type Target = TopicNameRef;\n\n    fn deref(&self) -> &TopicNameRef {\n        unsafe { TopicNameRef::new_unchecked(&self.0) }\n    }\n}\n\nimpl DerefMut for TopicName {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { TopicNameRef::new_mut_unchecked(&mut self.0) }\n    }\n}\n\nimpl Borrow<TopicNameRef> for TopicName {\n    fn borrow(&self) -> &TopicNameRef {\n        Deref::deref(self)\n    }\n}\n\nimpl BorrowMut<TopicNameRef> for TopicName {\n    fn borrow_mut(&mut self) -> &mut TopicNameRef {\n        DerefMut::deref_mut(self)\n    }\n}\n\nimpl Encodable for TopicName {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self.0[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self.0[..]).encoded_length()\n    }\n}\n\nimpl Decodable for TopicName {\n    type Error = TopicNameDecodeError;\n    type Cond = ();\n\n    fn decode_with<R: Read>(reader: &mut R, _rest: ()) -> Result<TopicName, TopicNameDecodeError> {\n        let topic_name = String::decode(reader)?;\n        Ok(TopicName::new(topic_name)?)\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"invalid topic filter ({0})\")]\npub struct TopicNameError(pub String);\n\n/// Errors while parsing topic names\n#[derive(Debug, thiserror::Error)]\n#[error(transparent)]\npub enum TopicNameDecodeError {\n    IoError(#[from] io::Error),\n    InvalidTopicName(#[from] TopicNameError),\n}\n\n/// Reference to a topic name\n#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]\n#[repr(transparent)]\npub struct TopicNameRef(str);\n\nimpl TopicNameRef {\n    /// Creates a new topic name from string\n    /// Return error if the string is not a valid topic name\n    pub fn new<S: AsRef<str> + ?Sized>(topic_name: &S) -> Result<&TopicNameRef, TopicNameError> {\n        let topic_name = topic_name.as_ref();\n        if is_invalid_topic_name(topic_name) {\n            Err(TopicNameError(topic_name.to_owned()))\n        } else {\n            Ok(unsafe { &*(topic_name as *const str as *const TopicNameRef) })\n        }\n    }\n\n    /// Creates a new topic name from string\n    /// Return error if the string is not a valid topic name\n    pub fn new_mut<S: AsMut<str> + ?Sized>(topic_name: &mut S) -> Result<&mut TopicNameRef, TopicNameError> {\n        let topic_name = topic_name.as_mut();\n        if is_invalid_topic_name(topic_name) {\n            Err(TopicNameError(topic_name.to_owned()))\n        } else {\n            Ok(unsafe { &mut *(topic_name as *mut str as *mut TopicNameRef) })\n        }\n    }\n\n    /// Creates a new topic name from string without validation\n    ///\n    /// # Safety\n    ///\n    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).\n    /// Creating a name from raw string may cause errors\n    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic_name: &S) -> &TopicNameRef {\n        let topic_name = topic_name.as_ref();\n        &*(topic_name as *const str as *const TopicNameRef)\n    }\n\n    /// Creates a new topic name from string without validation\n    ///\n    /// # Safety\n    ///\n    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).\n    /// Creating a name from raw string may cause errors\n    pub unsafe fn new_mut_unchecked<S: AsMut<str> + ?Sized>(topic_name: &mut S) -> &mut TopicNameRef {\n        let topic_name = topic_name.as_mut();\n        &mut *(topic_name as *mut str as *mut TopicNameRef)\n    }\n\n    /// Check if this topic name is only for server.\n    ///\n    /// Topic names that beginning with a '$' character are reserved for servers\n    pub fn is_server_specific(&self) -> bool {\n        self.0.starts_with('$')\n    }\n}\n\nimpl Deref for TopicNameRef {\n    type Target = str;\n\n    fn deref(&self) -> &str {\n        &self.0\n    }\n}\n\nimpl ToOwned for TopicNameRef {\n    type Owned = TopicName;\n\n    fn to_owned(&self) -> Self::Owned {\n        TopicName(self.0.to_owned())\n    }\n}\n\nimpl Encodable for TopicNameRef {\n    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {\n        (&self.0[..]).encode(writer)\n    }\n\n    fn encoded_length(&self) -> u32 {\n        (&self.0[..]).encoded_length()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn topic_name_sys() {\n        let topic_name = \"$SYS\".to_owned();\n        TopicName::new(topic_name).unwrap();\n\n        let topic_name = \"$SYS/broker/connection/test.cosm-energy/state\".to_owned();\n        TopicName::new(topic_name).unwrap();\n    }\n\n    #[test]\n    fn topic_name_slash() {\n        TopicName::new(\"/\").unwrap();\n    }\n\n    #[test]\n    fn topic_name_basic() {\n        TopicName::new(\"/finance\").unwrap();\n        TopicName::new(\"/finance//def\").unwrap();\n    }\n}\n"
  }
]