use bitflags::bitflags;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use std::ffi::CString;
use std::mem;
use std::os::raw::{c_char, c_void};
use std::slice;
use crate::context::Context;
use crate::error::{Error, Result};
use crate::iter::{
Ancestors, Array, Getnext, IterSchemaFlags, NodeIterable, Set, Siblings,
Traverse,
};
use crate::utils::*;
use libyang5_sys as ffi;
#[derive(Clone, Debug)]
pub struct SchemaModule<'a> {
pub(crate) context: &'a Context,
pub(crate) raw: *mut ffi::lys_module,
}
#[derive(Clone, Debug)]
pub struct SchemaSubmodule<'a> {
pub(crate) module: &'a SchemaModule<'a>,
pub(crate) raw: *mut ffi::lysp_submodule,
}
#[derive(Clone, Debug)]
pub struct SchemaImport<'a> {
pub(crate) context: &'a Context,
pub(crate) raw: *mut ffi::lysp_import,
}
#[allow(clippy::upper_case_acronyms)]
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SchemaInputFormat {
YANG = ffi::LYS_INFORMAT::LYS_IN_YANG,
YIN = ffi::LYS_INFORMAT::LYS_IN_YIN,
}
#[allow(clippy::upper_case_acronyms)]
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SchemaOutputFormat {
YANG = ffi::LYS_OUTFORMAT::LYS_OUT_YANG,
YIN = ffi::LYS_OUTFORMAT::LYS_OUT_YIN,
TREE = ffi::LYS_OUTFORMAT::LYS_OUT_TREE,
}
#[allow(clippy::upper_case_acronyms)]
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SchemaPathFormat {
LOG = ffi::LYSC_PATH_TYPE::LYSC_PATH_LOG,
DATA = ffi::LYSC_PATH_TYPE::LYSC_PATH_DATA,
}
bitflags! {
pub struct SchemaPrinterFlags: u32 {
const SHRINK = ffi::LYS_PRINT_SHRINK;
const NO_SUBSTMT = ffi::LYS_PRINT_NO_SUBSTMT;
}
}
#[derive(Clone, Debug)]
pub struct SchemaNode<'a> {
pub(crate) context: &'a Context,
pub(crate) raw: *mut ffi::lysc_node,
kind: SchemaNodeKind,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SchemaNodeKind {
Container,
Case,
Choice,
Leaf,
LeafList,
List,
AnyXml,
AnyData,
Rpc,
Input,
Output,
Action,
Notification,
}
#[derive(Clone, Debug)]
pub struct SchemaStmtMust<'a> {
raw: *mut ffi::lysc_must,
_marker: std::marker::PhantomData<&'a Context>,
}
#[derive(Clone, Debug)]
pub struct SchemaStmtWhen<'a> {
raw: *mut ffi::lysc_when,
_marker: std::marker::PhantomData<&'a Context>,
}
#[derive(Clone, Debug)]
pub struct SchemaLeafType<'a> {
context: &'a Context,
raw: *mut ffi::lysc_type,
}
#[derive(Clone, Debug)]
pub struct SchemaExtInstance {
pub(crate) raw: *mut ffi::lysc_ext_instance,
}
#[derive(Copy, Clone, Debug, PartialEq, FromPrimitive)]
pub enum DataValueType {
Unknown = 0,
Binary = 1,
Uint8 = 2,
Uint16 = 3,
Uint32 = 4,
Uint64 = 5,
String = 6,
Bits = 7,
Bool = 8,
Dec64 = 9,
Empty = 10,
Enum = 11,
IdentityRef = 12,
InstanceId = 13,
LeafRef = 14,
Union = 15,
Int8 = 16,
Int16 = 17,
Int32 = 18,
Int64 = 19,
}
#[derive(Clone, Debug, PartialEq)]
pub enum DataValue {
Uint8(u8),
Uint16(u16),
Uint32(u32),
Uint64(u64),
Bool(bool),
Empty,
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
Other(String),
}
impl<'a> SchemaModule<'a> {
pub fn as_raw(&self) -> *mut ffi::lys_module {
self.raw
}
pub fn name(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).name })
}
pub fn revision(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).revision })
}
pub fn namespace(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).ns })
}
pub fn prefix(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).prefix })
}
pub fn filepath(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).filepath })
}
pub fn organization(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).org })
}
pub fn contact(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).contact })
}
pub fn description(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).dsc })
}
pub fn reference(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).ref_ })
}
pub fn set_implemented(&self) -> Result<()> {
let ret =
unsafe { ffi::lys_set_implemented(self.raw, std::ptr::null_mut()) };
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
Ok(())
}
pub fn is_implemented(&self) -> bool {
unsafe { (*self.raw).implemented != 0 }
}
pub fn feature_value(&self, feature: &str) -> Result<bool> {
let feature = CString::new(feature).unwrap();
let ret = unsafe { ffi::lys_feature_value(self.raw, feature.as_ptr()) };
match ret {
ffi::LY_ERR::LY_SUCCESS => Ok(true),
ffi::LY_ERR::LY_ENOT => Ok(false),
_ => Err(Error::new(self.context)),
}
}
pub fn get_submodule(
&self,
name: &str,
revision: Option<&str>,
) -> Option<SchemaSubmodule<'_>> {
let name = CString::new(name).unwrap();
let revision_cstr;
let revision_ptr = match revision {
Some(revision) => {
revision_cstr = CString::new(revision).unwrap();
revision_cstr.as_ptr()
}
None => std::ptr::null(),
};
let module = unsafe {
ffi::ly_ctx_get_submodule2(self.raw, name.as_ptr(), revision_ptr)
};
if module.is_null() {
return None;
}
Some(unsafe { SchemaSubmodule::from_raw(self, module as _) })
}
pub fn get_submodule_latest(
&self,
name: &str,
) -> Option<SchemaSubmodule<'_>> {
let name = CString::new(name).unwrap();
let module = unsafe {
ffi::ly_ctx_get_submodule2_latest(self.raw, name.as_ptr())
};
if module.is_null() {
return None;
}
Some(unsafe { SchemaSubmodule::from_raw(self, module as _) })
}
#[cfg(not(target_os = "windows"))]
pub fn print_file<F: std::os::unix::io::AsRawFd>(
&self,
fd: F,
format: SchemaOutputFormat,
options: SchemaPrinterFlags,
) -> Result<()> {
let ret = unsafe {
ffi::lys_print_fd(
fd.as_raw_fd(),
self.raw,
format as u32,
options.bits(),
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
Ok(())
}
#[cfg(target_os = "windows")]
pub fn print_file(
&self,
file: impl std::os::windows::io::AsRawHandle,
format: SchemaOutputFormat,
options: SchemaPrinterFlags,
) -> Result<()> {
use libc::open_osfhandle;
let raw_handle = file.as_raw_handle();
let fd = unsafe { open_osfhandle(raw_handle as isize, 0) };
let ret = unsafe {
ffi::lys_print_fd(fd, self.raw, format as u32, options.bits())
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
Ok(())
}
pub fn print_string(
&self,
format: SchemaOutputFormat,
options: SchemaPrinterFlags,
) -> Result<String> {
let mut cstr = std::ptr::null_mut();
let cstr_ptr = &mut cstr;
let ret = unsafe {
ffi::lys_print_mem(
cstr_ptr,
self.raw,
format as u32,
options.bits(),
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
Ok(char_ptr_to_string(cstr, true))
}
pub fn data(&self) -> Siblings<'a, SchemaNode<'a>> {
let compiled = unsafe { (*self.raw).compiled };
let rdata = if compiled.is_null() {
std::ptr::null()
} else {
unsafe { (*compiled).data }
};
let data =
unsafe { SchemaNode::from_raw_opt(self.context, rdata as *mut _) };
Siblings::new(data)
}
pub fn rpcs(&self) -> Siblings<'a, SchemaNode<'a>> {
let compiled = unsafe { (*self.raw).compiled };
let rdata = if compiled.is_null() {
std::ptr::null()
} else {
unsafe { (*compiled).rpcs }
};
let rpcs =
unsafe { SchemaNode::from_raw_opt(self.context, rdata as *mut _) };
Siblings::new(rpcs)
}
pub fn notifications(&self) -> Siblings<'a, SchemaNode<'a>> {
let compiled = unsafe { (*self.raw).compiled };
let rdata = if compiled.is_null() {
std::ptr::null()
} else {
unsafe { (*compiled).notifs }
};
let notifications =
unsafe { SchemaNode::from_raw_opt(self.context, rdata as *mut _) };
Siblings::new(notifications)
}
pub fn extensions(
&self,
) -> impl Iterator<Item = SchemaExtInstance> + use<'a> {
let compiled = unsafe { (*self.raw).compiled };
if compiled.is_null() {
return Array::new(self.context, std::ptr::null_mut(), 0);
}
let array = unsafe { (*compiled).exts };
let ptr_size = mem::size_of::<ffi::lysc_ext_instance>();
Array::new(self.context, array as *mut _, ptr_size)
}
pub fn top_level_nodes(
&self,
flags: IterSchemaFlags,
) -> impl Iterator<Item = SchemaNode<'a>> {
Getnext::new(flags, None, Some(self.clone()))
}
pub fn traverse(&self) -> impl Iterator<Item = SchemaNode<'a>> {
let data = self.data().flat_map(|snode| snode.traverse());
let rpcs = self.rpcs().flat_map(|snode| snode.traverse());
let notifications =
self.notifications().flat_map(|snode| snode.traverse());
data.chain(rpcs).chain(notifications)
}
pub fn imports(&self) -> impl Iterator<Item = SchemaImport<'a>> {
let parsed = unsafe { (*self.raw).parsed };
if parsed.is_null() {
return Array::new(self.context, std::ptr::null_mut(), 0);
}
let array = unsafe { (*parsed).imports };
let ptr_size = mem::size_of::<ffi::lysp_import>();
Array::new(self.context, array as *mut _, ptr_size)
}
pub fn parse_string(
context: &'a Context,
data: &str,
schema_input_format: SchemaInputFormat,
) -> Result<Self> {
let mut raw: *mut ffi::lys_module = std::ptr::null_mut();
let data = CString::new(data).unwrap();
let ret = unsafe {
ffi::lys_parse_mem(
context.raw,
data.as_ptr(),
schema_input_format as u32,
&mut raw,
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(context));
}
Ok(Self { context, raw })
}
#[cfg(not(target_os = "windows"))]
pub fn parse_file<F: std::os::unix::io::AsRawFd>(
context: &'a Context,
fd: F,
schema_input_format: SchemaInputFormat,
) -> Result<Self> {
let mut raw: *mut ffi::lys_module = std::ptr::null_mut();
let ret = unsafe {
ffi::lys_parse_fd(
context.raw,
fd.as_raw_fd(),
schema_input_format as u32,
&mut raw,
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(context));
}
Ok(Self { context, raw })
}
#[cfg(target_os = "windows")]
pub fn parse_file<F: std::os::unix::io::AsRawFd>(
context: &'a Context,
file: impl std::os::windows::io::AsRawHandle,
schema_input_format: SchemaInputFormat,
) -> Result<Self> {
use libc::open_osfhandle;
let raw_handle = file.as_raw_handle();
let fd = unsafe { open_osfhandle(raw_handle as isize, 0) };
let mut raw: *mut ffi::lys_module = std::ptr::null_mut();
let ret = unsafe {
ffi::lys_parse_fd(
context.raw,
fd.as_raw_fd(),
schema_input_format as u32,
&mut raw,
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(context));
}
Ok(Self { context, raw })
}
}
unsafe impl<'a> Binding<'a> for SchemaModule<'a> {
type CType = ffi::lys_module;
type Container = Context;
unsafe fn from_raw(
context: &'a Context,
raw: *mut ffi::lys_module,
) -> SchemaModule<'a> {
SchemaModule { context, raw }
}
}
impl PartialEq for SchemaModule<'_> {
fn eq(&self, other: &SchemaModule<'_>) -> bool {
self.raw == other.raw
}
}
unsafe impl Send for SchemaModule<'_> {}
unsafe impl Sync for SchemaModule<'_> {}
impl SchemaSubmodule<'_> {
pub fn as_raw(&self) -> *mut ffi::lysp_submodule {
self.raw
}
pub fn print_string(
&self,
format: SchemaOutputFormat,
options: SchemaPrinterFlags,
) -> Result<String> {
let mut cstr = std::ptr::null_mut();
let cstr_ptr = &mut cstr;
let mut ly_out = std::ptr::null_mut();
let ret = unsafe { ffi::ly_out_new_memory(cstr_ptr, 0, &mut ly_out) };
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.module.context));
}
let ret = unsafe {
ffi::lys_print_submodule(
ly_out,
self.raw,
format as u32,
0,
options.bits(),
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.module.context));
}
let string = char_ptr_to_string(cstr, false);
unsafe { ffi::ly_out_free(ly_out, None, 0) };
Ok(string)
}
}
unsafe impl<'a> Binding<'a> for SchemaSubmodule<'a> {
type CType = ffi::lysp_submodule;
type Container = SchemaModule<'a>;
unsafe fn from_raw(
module: &'a SchemaModule<'a>,
raw: *mut ffi::lysp_submodule,
) -> SchemaSubmodule<'a> {
SchemaSubmodule { module, raw }
}
}
impl PartialEq for SchemaSubmodule<'_> {
fn eq(&self, other: &SchemaSubmodule<'_>) -> bool {
self.raw == other.raw
}
}
unsafe impl Send for SchemaSubmodule<'_> {}
unsafe impl Sync for SchemaSubmodule<'_> {}
impl<'a> SchemaImport<'a> {
pub fn module(&self) -> SchemaModule<'_> {
let module = unsafe { (*self.raw).module };
unsafe { SchemaModule::from_raw(self.context, module) }
}
pub fn name(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).name })
}
pub fn prefix(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).prefix })
}
pub fn description(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).dsc })
}
pub fn reference(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).ref_ })
}
}
unsafe impl<'a> Binding<'a> for SchemaImport<'a> {
type CType = ffi::lysp_import;
type Container = Context;
unsafe fn from_raw(
context: &'a Context,
raw: *mut ffi::lysp_import,
) -> SchemaImport<'a> {
SchemaImport { context, raw }
}
}
unsafe impl Send for SchemaImport<'_> {}
unsafe impl Sync for SchemaImport<'_> {}
impl<'a> SchemaNode<'a> {
pub fn as_raw(&self) -> *mut ffi::lysc_node {
self.raw
}
#[doc(hidden)]
fn check_flag(&self, flag: u32) -> bool {
let flags = unsafe { (*self.raw).flags } as u32;
flags & flag != 0
}
pub fn module(&self) -> SchemaModule<'_> {
let module = unsafe { (*self.raw).module };
unsafe { SchemaModule::from_raw(self.context, module) }
}
pub fn kind(&self) -> SchemaNodeKind {
self.kind
}
pub fn name(&self) -> &str {
char_ptr_to_str(unsafe { (*self.raw).name })
}
pub fn description(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).dsc })
}
pub fn reference(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).ref_ })
}
pub fn path(&self, format: SchemaPathFormat) -> String {
let buf = std::mem::MaybeUninit::<[c_char; 4096]>::uninit();
let mut buf = unsafe { buf.assume_init() };
let ret = unsafe {
ffi::lysc_path(self.raw, format as u32, buf.as_mut_ptr(), buf.len())
};
if ret.is_null() {
panic!("Failed to generate path of the schema node");
}
char_ptr_to_string(buf.as_ptr(), false)
}
pub fn find_xpath(&self, xpath: &str) -> Result<Set<'_, SchemaNode<'_>>> {
let xpath = CString::new(xpath).unwrap();
let mut set = std::ptr::null_mut();
let set_ptr = &mut set;
let options = 0u32;
let ret = unsafe {
ffi::lys_find_xpath(
std::ptr::null(),
self.raw,
xpath.as_ptr(),
options,
set_ptr,
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
let rnodes_count = unsafe { (*set).count } as usize;
let slice = if rnodes_count == 0 {
&[]
} else {
let rnodes = unsafe { (*set).__bindgen_anon_1.snodes };
unsafe { slice::from_raw_parts(rnodes, rnodes_count) }
};
Ok(Set::new(self.context, slice))
}
pub fn find_path(&self, path: &str) -> Result<SchemaNode<'_>> {
let path = CString::new(path).unwrap();
let rnode = unsafe {
ffi::lys_find_path(std::ptr::null(), self.raw, path.as_ptr(), 0)
};
if rnode.is_null() {
return Err(Error::new(self.context));
}
Ok(unsafe { SchemaNode::from_raw(self.context, rnode as *mut _) })
}
pub fn is_config(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Case
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_CONFIG_W),
_ => false,
}
}
pub fn is_state(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Case
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_CONFIG_R),
_ => false,
}
}
pub fn is_status_current(&self) -> bool {
self.check_flag(ffi::LYS_STATUS_CURR)
}
pub fn is_status_deprecated(&self) -> bool {
self.check_flag(ffi::LYS_STATUS_DEPRC)
}
pub fn is_status_obsolete(&self) -> bool {
self.check_flag(ffi::LYS_STATUS_OBSLT)
}
pub fn is_mandatory(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_MAND_TRUE),
_ => false,
}
}
pub fn is_np_container(&self) -> bool {
match self.kind {
SchemaNodeKind::Container => !self.check_flag(ffi::LYS_PRESENCE),
_ => false,
}
}
pub fn is_list_key(&self) -> bool {
match self.kind {
SchemaNodeKind::Leaf => self.check_flag(ffi::LYS_KEY),
_ => false,
}
}
pub fn is_keyless_list(&self) -> bool {
match self.kind {
SchemaNodeKind::List => self.check_flag(ffi::LYS_KEYLESS),
_ => false,
}
}
pub fn is_user_ordered(&self) -> bool {
match self.kind {
SchemaNodeKind::LeafList | SchemaNodeKind::List => {
self.check_flag(ffi::LYS_ORDBY_USER)
}
_ => false,
}
}
pub fn is_schema_only(&self) -> bool {
matches!(self.kind(), SchemaNodeKind::Choice | SchemaNodeKind::Case)
}
pub fn is_within_input(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Case
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_IS_INPUT),
_ => false,
}
}
pub fn is_within_output(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Case
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_IS_OUTPUT),
_ => false,
}
}
pub fn is_within_notification(&self) -> bool {
match self.kind {
SchemaNodeKind::Container
| SchemaNodeKind::Case
| SchemaNodeKind::Choice
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList
| SchemaNodeKind::List
| SchemaNodeKind::AnyData => self.check_flag(ffi::LYS_IS_NOTIF),
_ => false,
}
}
pub fn has_default(&self) -> bool {
match self.kind {
SchemaNodeKind::Case
| SchemaNodeKind::Leaf
| SchemaNodeKind::LeafList => self.check_flag(ffi::LYS_SET_DFLT),
_ => false,
}
}
pub fn default_value_canonical(&self) -> Result<Option<String>> {
if self.kind() != SchemaNodeKind::Leaf {
return Ok(None);
}
let mut canonical = std::ptr::null();
let ret = unsafe {
let dflt = (*(self.raw as *const ffi::lysc_node_leaf)).dflt;
ffi::lyd_value_validate_dflt(
self.raw,
dflt.str_,
dflt.prefixes,
std::ptr::null(),
std::ptr::null_mut(),
&mut canonical,
)
};
if ret != ffi::LY_ERR::LY_SUCCESS {
return Err(Error::new(self.context));
}
let canonical_string = char_ptr_to_opt_string(canonical, false);
unsafe {
ffi::lydict_remove(self.context.raw, canonical);
};
Ok(canonical_string)
}
pub fn default_case(&self) -> Option<SchemaNode<'_>> {
let default = unsafe {
match self.kind() {
SchemaNodeKind::Choice => {
(*(self.raw as *mut ffi::lysc_node_choice)).dflt
}
_ => return None,
}
};
unsafe { SchemaNode::from_raw_opt(self.context, default as *mut _) }
}
pub fn leaf_type(&self) -> Option<SchemaLeafType<'_>> {
let raw = unsafe {
match self.kind() {
SchemaNodeKind::Leaf => {
(*(self.raw as *mut ffi::lysc_node_leaf)).type_
}
SchemaNodeKind::LeafList => {
(*(self.raw as *mut ffi::lysc_node_leaflist)).type_
}
_ => return None,
}
};
let ltype = unsafe { SchemaLeafType::from_raw(self.context, raw) };
Some(ltype)
}
pub fn units(&self) -> Option<&str> {
let units = unsafe {
match self.kind() {
SchemaNodeKind::Leaf => {
(*(self.raw as *mut ffi::lysc_node_leaf)).units
}
SchemaNodeKind::LeafList => {
(*(self.raw as *mut ffi::lysc_node_leaflist)).units
}
_ => return None,
}
};
char_ptr_to_opt_str(units)
}
pub fn min_elements(&self) -> Option<u32> {
let min = unsafe {
match self.kind() {
SchemaNodeKind::LeafList => {
(*(self.raw as *mut ffi::lysc_node_leaflist)).min
}
SchemaNodeKind::List => {
(*(self.raw as *mut ffi::lysc_node_list)).min
}
_ => return None,
}
};
if min != 0 {
Some(min)
} else {
None
}
}
pub fn max_elements(&self) -> Option<u32> {
let max = unsafe {
match self.kind() {
SchemaNodeKind::LeafList => {
(*(self.raw as *mut ffi::lysc_node_leaflist)).max
}
SchemaNodeKind::List => {
(*(self.raw as *mut ffi::lysc_node_list)).max
}
_ => return None,
}
};
if max != u32::MAX {
Some(max)
} else {
None
}
}
pub fn musts(&self) -> Option<Array<'_, SchemaStmtMust<'_>>> {
let array = unsafe { ffi::lysc_node_musts(self.raw) };
let ptr_size = mem::size_of::<ffi::lysc_must>();
Some(Array::new(self.context, array as *mut _, ptr_size))
}
pub fn whens(&self) -> Array<'_, SchemaStmtWhen<'_>> {
let array = unsafe { ffi::lysc_node_when(self.raw) };
let ptr_size = mem::size_of::<ffi::lysc_when>();
Array::new(self.context, array as *mut _, ptr_size)
}
pub fn actions(&self) -> impl Iterator<Item = SchemaNode<'a>> + 'a {
let rnode = unsafe {
match self.kind {
SchemaNodeKind::Container => {
(*(self.raw as *mut ffi::lysc_node_container)).actions
}
SchemaNodeKind::List => {
(*(self.raw as *mut ffi::lysc_node_list)).actions
}
_ => std::ptr::null_mut(),
}
};
let node =
unsafe { SchemaNode::from_raw_opt(self.context, rnode as *mut _) };
Siblings::new(node)
}
pub fn notifications(&self) -> impl Iterator<Item = SchemaNode<'a>> + 'a {
let rnode = unsafe {
match self.kind {
SchemaNodeKind::Container => {
(*(self.raw as *mut ffi::lysc_node_container)).notifs
}
SchemaNodeKind::List => {
(*(self.raw as *mut ffi::lysc_node_list)).notifs
}
_ => std::ptr::null_mut(),
}
};
let node =
unsafe { SchemaNode::from_raw_opt(self.context, rnode as *mut _) };
Siblings::new(node)
}
pub fn input(
&self,
) -> Option<(Siblings<'_, SchemaNode<'_>>, Array<'_, SchemaStmtMust<'_>>)>
{
match self.kind {
SchemaNodeKind::Rpc | SchemaNodeKind::Action => {
let raw = self.raw as *mut ffi::lysc_node_action;
let input = unsafe { (*raw).input };
let rnode = input.child;
let rmusts = input.musts;
let node =
unsafe { SchemaNode::from_raw_opt(self.context, rnode) };
let nodes = Siblings::new(node);
let ptr_size = mem::size_of::<ffi::lysc_must>();
let musts = Array::new(self.context, rmusts, ptr_size);
Some((nodes, musts))
}
_ => None,
}
}
pub fn output(
&self,
) -> Option<(Siblings<'_, SchemaNode<'_>>, Array<'_, SchemaStmtMust<'_>>)>
{
match self.kind {
SchemaNodeKind::Rpc | SchemaNodeKind::Action => {
let raw = self.raw as *mut ffi::lysc_node_action;
let output = unsafe { (*raw).output };
let rnode = output.child;
let rmusts = output.musts;
let node =
unsafe { SchemaNode::from_raw_opt(self.context, rnode) };
let nodes = Siblings::new(node);
let ptr_size = mem::size_of::<ffi::lysc_must>();
let musts = Array::new(self.context, rmusts, ptr_size);
Some((nodes, musts))
}
_ => None,
}
}
pub fn ancestors(&self) -> Ancestors<'a, SchemaNode<'a>> {
let parent = self.parent();
Ancestors::new(parent)
}
pub fn inclusive_ancestors(&self) -> Ancestors<'a, SchemaNode<'a>> {
Ancestors::new(Some(self.clone()))
}
pub fn siblings(&self) -> Siblings<'a, SchemaNode<'a>> {
let sibling = self.next_sibling();
Siblings::new(sibling)
}
pub fn inclusive_siblings(&self) -> Siblings<'a, SchemaNode<'a>> {
Siblings::new(Some(self.clone()))
}
pub fn children(&self) -> Siblings<'a, SchemaNode<'a>> {
let child = self.first_child();
Siblings::new(child)
}
pub fn all_children(&self) -> impl Iterator<Item = SchemaNode<'a>> {
let child = self.first_child();
Siblings::new(child)
.chain(self.actions())
.chain(self.notifications())
}
pub fn children2(
&self,
flags: IterSchemaFlags,
) -> impl Iterator<Item = SchemaNode<'a>> {
Getnext::new(flags, Some(self.clone()), None)
}
pub fn traverse(&self) -> Traverse<'a, SchemaNode<'a>> {
Traverse::new(self.clone())
}
pub fn list_keys(&self) -> impl Iterator<Item = SchemaNode<'a>> {
self.children().filter(|snode| snode.is_list_key())
}
pub unsafe fn set_private(&self, ptr: *mut c_void) {
(*self.raw).priv_ = ptr;
}
pub fn get_private(&self) -> Option<*mut c_void> {
let priv_ = unsafe { (*self.raw).priv_ };
if priv_.is_null() {
None
} else {
Some(priv_)
}
}
}
unsafe impl<'a> Binding<'a> for SchemaNode<'a> {
type CType = ffi::lysc_node;
type Container = Context;
unsafe fn from_raw(
context: &'a Context,
raw: *mut ffi::lysc_node,
) -> SchemaNode<'a> {
let nodetype = unsafe { (*raw).nodetype } as u32;
let kind = match nodetype {
ffi::LYS_CONTAINER => SchemaNodeKind::Container,
ffi::LYS_CASE => SchemaNodeKind::Case,
ffi::LYS_CHOICE => SchemaNodeKind::Choice,
ffi::LYS_LEAF => SchemaNodeKind::Leaf,
ffi::LYS_LEAFLIST => SchemaNodeKind::LeafList,
ffi::LYS_LIST => SchemaNodeKind::List,
ffi::LYS_ANYXML => SchemaNodeKind::AnyXml,
ffi::LYS_ANYDATA => SchemaNodeKind::AnyData,
ffi::LYS_ACTION => SchemaNodeKind::Action,
ffi::LYS_RPC => SchemaNodeKind::Rpc,
ffi::LYS_INPUT => SchemaNodeKind::Input,
ffi::LYS_OUTPUT => SchemaNodeKind::Output,
ffi::LYS_NOTIF => SchemaNodeKind::Notification,
_ => panic!("unknown node type"),
};
SchemaNode { context, raw, kind }
}
}
impl<'a> NodeIterable<'a> for SchemaNode<'a> {
fn parent(&self) -> Option<SchemaNode<'a>> {
let rparent = unsafe { (*self.raw).parent };
unsafe { SchemaNode::from_raw_opt(self.context, rparent) }
}
fn next_sibling(&self) -> Option<SchemaNode<'a>> {
let rnext = unsafe { (*self.raw).next };
unsafe { SchemaNode::from_raw_opt(self.context, rnext) }
}
fn first_child(&self) -> Option<SchemaNode<'a>> {
let rchild = unsafe { ffi::lysc_node_child(&*self.raw) };
unsafe { SchemaNode::from_raw_opt(self.context, rchild as *mut _) }
}
}
impl PartialEq for SchemaNode<'_> {
fn eq(&self, other: &SchemaNode<'_>) -> bool {
self.raw == other.raw
}
}
unsafe impl Send for SchemaNode<'_> {}
unsafe impl Sync for SchemaNode<'_> {}
impl SchemaStmtMust<'_> {
pub fn as_raw(&self) -> *mut ffi::lysc_must {
self.raw
}
pub fn description(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).dsc })
}
pub fn reference(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).ref_ })
}
pub fn error_msg(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).emsg })
}
pub fn error_apptag(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).eapptag })
}
}
unsafe impl<'a> Binding<'a> for SchemaStmtMust<'a> {
type CType = ffi::lysc_must;
type Container = Context;
unsafe fn from_raw(
_context: &'a Context,
raw: *mut ffi::lysc_must,
) -> SchemaStmtMust<'a> {
SchemaStmtMust {
raw,
_marker: std::marker::PhantomData,
}
}
}
unsafe impl Send for SchemaStmtMust<'_> {}
unsafe impl Sync for SchemaStmtMust<'_> {}
impl SchemaStmtWhen<'_> {
pub fn as_raw(&self) -> *mut ffi::lysc_when {
self.raw
}
pub fn description(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).dsc })
}
pub fn reference(&self) -> Option<&str> {
char_ptr_to_opt_str(unsafe { (*self.raw).ref_ })
}
}
unsafe impl<'a> Binding<'a> for SchemaStmtWhen<'a> {
type CType = *mut ffi::lysc_when;
type Container = Context;
unsafe fn from_raw(
_context: &'a Context,
raw: *mut *mut ffi::lysc_when,
) -> SchemaStmtWhen<'a> {
let raw = unsafe { *raw };
SchemaStmtWhen {
raw,
_marker: std::marker::PhantomData,
}
}
}
unsafe impl Send for SchemaStmtWhen<'_> {}
unsafe impl Sync for SchemaStmtWhen<'_> {}
impl SchemaLeafType<'_> {
pub fn as_raw(&self) -> *mut ffi::lysc_type {
self.raw
}
pub fn base_type(&self) -> DataValueType {
let base_type = unsafe { (*self.raw).basetype };
DataValueType::from_u32(base_type).unwrap()
}
pub fn typedef_name(&self) -> Option<String> {
let typedef = unsafe { (*self.raw).name };
char_ptr_to_opt_string(typedef, false)
}
pub fn leafref_real_type(&self) -> Option<SchemaLeafType<'_>> {
if self.base_type() != DataValueType::LeafRef {
return None;
}
let leafref = self.raw as *mut ffi::lysc_type_leafref;
let real_type = unsafe { (*leafref).realtype };
let ltype =
unsafe { SchemaLeafType::from_raw(self.context, real_type) };
Some(ltype)
}
}
unsafe impl<'a> Binding<'a> for SchemaLeafType<'a> {
type CType = ffi::lysc_type;
type Container = Context;
unsafe fn from_raw(
context: &'a Context,
raw: *mut ffi::lysc_type,
) -> SchemaLeafType<'a> {
SchemaLeafType { context, raw }
}
}
unsafe impl Send for SchemaLeafType<'_> {}
unsafe impl Sync for SchemaLeafType<'_> {}
impl SchemaExtInstance {
pub fn as_raw(&self) -> *mut ffi::lysc_ext_instance {
self.raw
}
pub fn argument(&self) -> Option<String> {
let argument = unsafe { (*self.raw).argument };
char_ptr_to_opt_string(argument, false)
}
}
unsafe impl<'a> Binding<'a> for SchemaExtInstance {
type CType = ffi::lysc_ext_instance;
type Container = Context;
unsafe fn from_raw(
_context: &'a Context,
raw: *mut ffi::lysc_ext_instance,
) -> SchemaExtInstance {
SchemaExtInstance { raw }
}
}
unsafe impl Send for SchemaExtInstance {}
unsafe impl Sync for SchemaExtInstance {}
impl DataValue {
pub(crate) unsafe fn from_raw(
context: &Context,
raw: *const ffi::lyd_value,
) -> DataValue {
let rtype = (*(*raw).realtype).basetype;
match rtype {
ffi::LY_DATA_TYPE::LY_TYPE_UINT8 => {
let value = (*raw).__bindgen_anon_1.uint8;
DataValue::Uint8(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_UINT16 => {
let value = (*raw).__bindgen_anon_1.uint16;
DataValue::Uint16(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_UINT32 => {
let value = (*raw).__bindgen_anon_1.uint32;
DataValue::Uint32(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_UINT64 => {
let value = (*raw).__bindgen_anon_1.uint64;
DataValue::Uint64(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_BOOL => {
let value = (*raw).__bindgen_anon_1.boolean != 0;
DataValue::Bool(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_INT8 => {
let value = (*raw).__bindgen_anon_1.int8;
DataValue::Int8(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_INT16 => {
let value = (*raw).__bindgen_anon_1.int16;
DataValue::Int16(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_INT32 => {
let value = (*raw).__bindgen_anon_1.int32;
DataValue::Int32(value)
}
ffi::LY_DATA_TYPE::LY_TYPE_INT64 => {
let value = (*raw).__bindgen_anon_1.int64;
DataValue::Int64(value)
}
_ => {
let mut canonical = (*raw)._canonical;
if canonical.is_null() {
canonical = ffi::lyd_value_get_canonical(context.raw, raw);
}
DataValue::Other(char_ptr_to_string(canonical, false))
}
}
}
}