bgpfu-netconf 0.1.0

A toolset for working with IRR data
Documentation
use std::io::Write;

use quick_xml::Writer;

use crate::{capabilities::Requirements, message::WriteError, session::Context, Error};

use super::{params::Required, Datastore, EmptyReply, Operation, WriteXml};

#[derive(Debug, Clone, Copy)]
pub struct Lock {
    target: Datastore,
}

impl Operation for Lock {
    const NAME: &'static str = "lock";
    const REQUIRED_CAPABILITIES: Requirements = Requirements::None;

    type Builder<'a> = Builder<'a>;
    type Reply = EmptyReply;
}

impl WriteXml for Lock {
    fn write_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), WriteError> {
        writer
            .create_element(Self::NAME)
            .write_inner_content(|writer| {
                writer
                    .create_element("target")
                    .write_inner_content(|writer| self.target.write_xml(writer))
                    .map(|_| ())
            })
            .map(|_| ())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Unlock {
    target: Datastore,
}

impl Operation for Unlock {
    const NAME: &'static str = "unlock";
    const REQUIRED_CAPABILITIES: Requirements = Requirements::None;

    type Builder<'a> = Builder<'a>;
    type Reply = EmptyReply;
}

impl WriteXml for Unlock {
    fn write_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), WriteError> {
        writer
            .create_element(Self::NAME)
            .write_inner_content(|writer| {
                writer
                    .create_element("target")
                    .write_inner_content(|writer| self.target.write_xml(writer))
                    .map(|_| ())
            })
            .map(|_| ())
    }
}

#[derive(Debug, Clone)]
#[must_use]
pub struct Builder<'a> {
    ctx: &'a Context,
    target: Required<Datastore>,
}

impl<'a> Builder<'a> {
    const fn new(ctx: &'a Context) -> Self {
        Self {
            ctx,
            target: Required::init(),
        }
    }

    pub fn target(mut self, target: Datastore) -> Result<Self, Error> {
        target.try_as_lock_target(self.ctx).map(|target| {
            self.target.set(target);
            self
        })
    }
}

impl<'a> super::Builder<'a, Lock> for Builder<'a> {
    fn new(ctx: &'a Context) -> Self {
        Self::new(ctx)
    }

    fn finish(self) -> Result<Lock, Error> {
        Ok(Lock {
            target: self.target.require::<Lock>("target")?,
        })
    }
}

impl<'a> super::Builder<'a, Unlock> for Builder<'a> {
    fn new(ctx: &'a Context) -> Self {
        Self::new(ctx)
    }

    fn finish(self) -> Result<Unlock, Error> {
        Ok(Unlock {
            target: self.target.require::<Unlock>("target")?,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::message::{
        rpc::{MessageId, Request},
        ClientMsg,
    };

    #[test]
    fn lock_request_to_xml() {
        let req = Request {
            message_id: MessageId(101),
            operation: Lock {
                target: Datastore::Running,
            },
        };
        let expect =
            r#"<rpc message-id="101"><lock><target><running/></target></lock></rpc>]]>]]>"#;
        assert_eq!(req.to_xml().unwrap(), expect);
    }

    #[test]
    fn unlock_request_to_xml() {
        let req = Request {
            message_id: MessageId(101),
            operation: Unlock {
                target: Datastore::Running,
            },
        };
        let expect =
            r#"<rpc message-id="101"><unlock><target><running/></target></unlock></rpc>]]>]]>"#;
        assert_eq!(req.to_xml().unwrap(), expect);
    }
}