netconf/message/rpc/operation/
cancel_commit.rs

1use std::io::Write;
2
3use quick_xml::{events::BytesText, Writer};
4
5use crate::{
6    capabilities::{Capability, Requirements},
7    message::WriteError,
8    session::Context,
9    Error,
10};
11
12use super::{EmptyReply, Operation, Token, WriteXml};
13
14#[derive(Debug, Clone)]
15pub struct CancelCommit {
16    persist_id: Option<Token>,
17}
18
19impl Operation for CancelCommit {
20    const NAME: &'static str = "cancel-commit";
21    const REQUIRED_CAPABILITIES: Requirements = Requirements::One(Capability::ConfirmedCommitV1_1);
22
23    type Builder<'a> = Builder<'a>;
24    type Reply = EmptyReply;
25}
26
27impl WriteXml for CancelCommit {
28    fn write_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), WriteError> {
29        let elem = writer.create_element("cancel-commit");
30        if let Some(ref token) = self.persist_id {
31            _ = elem.write_inner_content(|writer| {
32                writer
33                    .create_element("persist-id")
34                    .write_text_content(BytesText::new(&token.to_string()))
35                    .map(|_| ())
36            })?;
37        } else {
38            _ = elem.write_empty()?;
39        };
40        Ok(())
41    }
42}
43
44#[derive(Debug, Clone)]
45#[must_use]
46pub struct Builder<'a> {
47    ctx: &'a Context,
48    persist_id: Option<Token>,
49}
50
51impl Builder<'_> {
52    pub fn persist_id(mut self, token: Option<Token>) -> Result<Self, Error> {
53        let required_capabilities = Requirements::One(Capability::ConfirmedCommitV1_1);
54        if required_capabilities.check(self.ctx.server_capabilities()) {
55            self.persist_id = token;
56            Ok(self)
57        } else {
58            Err(Error::UnsupportedOperationParameter {
59                operation_name: CancelCommit::NAME,
60                param_name: "persist-id",
61                required_capabilities,
62            })
63        }
64    }
65}
66
67impl<'a> super::Builder<'a, CancelCommit> for Builder<'a> {
68    fn new(ctx: &'a Context) -> Self {
69        Self {
70            ctx,
71            persist_id: None,
72        }
73    }
74
75    fn finish(self) -> Result<CancelCommit, Error> {
76        Ok(CancelCommit {
77            persist_id: self.persist_id,
78        })
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use crate::message::{
86        rpc::{MessageId, Request},
87        ClientMsg,
88    };
89
90    #[test]
91    fn non_persisted_request_to_xml() {
92        let req = Request {
93            message_id: MessageId(101),
94            operation: CancelCommit { persist_id: None },
95        };
96        let expect = r#"<rpc message-id="101"><cancel-commit/></rpc>]]>]]>"#;
97        assert_eq!(req.to_xml().unwrap(), expect);
98    }
99
100    #[test]
101    fn persisted_request_to_xml() {
102        let token = Token::generate();
103        let req = Request {
104            message_id: MessageId(101),
105            operation: CancelCommit {
106                persist_id: Some(token.clone()),
107            },
108        };
109        let expect = format!(
110            r#"<rpc message-id="101"><cancel-commit><persist-id>{token}</persist-id></cancel-commit></rpc>]]>]]>"#
111        );
112        assert_eq!(req.to_xml().unwrap(), expect);
113    }
114}