1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::sync::Arc;
use std::vec::Vec;
use {Publish, TopicPath, PacketIdentifier, QoS, LastWill, Error, Result};

#[derive(Debug, Clone)]
pub struct Message {
    pub topic: TopicPath,
    pub qos: QoS,
    pub retain: bool,
    // Only for QoS 1,2
    pub pid: Option<PacketIdentifier>,
    pub payload: Arc<Vec<u8>>
}

impl Message {
    pub fn from_pub(publish: Box<Publish>) -> Result<Box<Message>> {
        let topic = TopicPath::from(publish.topic_name.as_str());
        if topic.wildcards {
            return Err(Error::TopicNameMustNotContainWildcard);
        }
        Ok(Box::new(Message {
            topic: topic,
            qos: publish.qos,
            retain: publish.retain,
            pid: publish.pid,
            payload: publish.payload.clone()
        }))
    }

    pub fn from_last_will(last_will: LastWill) -> Box<Message> {
        let topic = TopicPath::from(last_will.topic);

        Box::new(Message {
            topic: topic,
            qos: last_will.qos,
            retain: last_will.retain,
            pid: None,
            payload: Arc::new(last_will.message.into_bytes())
        })
    }

    pub fn to_pub(&self, qos: Option<QoS>, dup: bool) -> Box<Publish> {
        let qos = qos.unwrap_or(self.qos);
        Box::new(Publish {
            dup: dup,
            qos: qos,
            retain: self.retain,
            topic_name: self.topic.path.clone(),
            pid: self.pid,
            payload: self.payload.clone()
        })
    }

    pub fn transform(&self, pid: Option<PacketIdentifier>, qos: Option<QoS>) -> Box<Message> {
        let pid = pid.or(self.pid);
        let qos = qos.unwrap_or(self.qos);
        Box::new(Message {
            topic: self.topic.clone(),
            qos: qos,
            retain: self.retain,
            pid: pid,
            payload: self.payload.clone()
        })
    }
}

#[cfg(test)]
mod test {
    use std::sync::Arc;
    use super::{Message};
    use {Publish, QoS, ToTopicPath, PacketIdentifier};

    #[test]
    fn message_to_pub_test() {
        let msg = Message {
            topic: "/a/b".to_topic_path().unwrap(),
            qos: QoS::AtLeastOnce,
            retain: false,
            pid: Some(PacketIdentifier(1)),
            payload: Arc::new(vec![0x80, 0x40])
        };
        let publish = msg.to_pub(None, false);

        assert_eq!(publish, Box::new(Publish {
            dup: false,
            qos: QoS::AtLeastOnce,
            retain: false,
            topic_name: "/a/b".to_owned(),
            pid: Some(PacketIdentifier(1)),
            payload: Arc::new(vec![0x80, 0x40])
        }));
    }

    #[test]
    fn message_from_pub_test() {
        let publish = Box::new(Publish {
            dup: true,
            qos: QoS::ExactlyOnce,
            retain: true,
            topic_name: "/a/b/c".to_owned(),
            pid: Some(PacketIdentifier(2)),
            payload: Arc::new(vec![0x10, 0x20, 0x30])
        });
        let msg = Message::from_pub(publish).unwrap();

        assert_eq!(msg.topic.path(), "/a/b/c".to_string());
        assert_eq!(msg.qos, QoS::ExactlyOnce);
        assert_eq!(msg.pid, Some(PacketIdentifier(2)));
        assert_eq!(msg.payload, Arc::new(vec![0x10, 0x20, 0x30]));
        assert!(msg.retain);
    }

    #[test]
    fn to_topic_name_test() {
        assert!("/a/b/c".to_topic_name().is_ok());
        assert!("/a/+/c".to_topic_name().is_err());
    }
}