mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Create bindings for idevice idevice
This commit is contained in:
96
ffi/src/errors.rs
Normal file
96
ffi/src/errors.rs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use idevice::IdeviceError;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum IdeviceErrorCode {
|
||||||
|
IdeviceSuccess = 0,
|
||||||
|
// Main library
|
||||||
|
Socket = -1,
|
||||||
|
Ssl = -2,
|
||||||
|
SslSetup = -3,
|
||||||
|
Plist = -4,
|
||||||
|
Utf8 = -5,
|
||||||
|
UnexpectedResponse = -6,
|
||||||
|
GetProhibited = -7,
|
||||||
|
SessionInactive = -8,
|
||||||
|
InvalidHostID = -9,
|
||||||
|
NoEstablishedConnection = -10,
|
||||||
|
HeartbeatSleepyTime = -11,
|
||||||
|
HeartbeatTimeout = -12,
|
||||||
|
NotFound = -13,
|
||||||
|
CdtunnelPacketTooShort = -14,
|
||||||
|
CdtunnelPacketInvalidMagic = -15,
|
||||||
|
PacketSizeMismatch = -16,
|
||||||
|
Json = -17,
|
||||||
|
DeviceNotFound = -18,
|
||||||
|
DeviceLocked = -19,
|
||||||
|
UsbConnectionRefused = -20,
|
||||||
|
UsbBadCommand = -21,
|
||||||
|
UsbBadDevice = -22,
|
||||||
|
UsbBadVersion = -23,
|
||||||
|
BadBuildManifest = -24,
|
||||||
|
ImageNotMounted = -25,
|
||||||
|
Reqwest = -26,
|
||||||
|
InternalError = -27,
|
||||||
|
Xpc = -28,
|
||||||
|
NsKeyedArchiveError = -29,
|
||||||
|
UnknownAuxValueType = -30,
|
||||||
|
UnknownChannel = -31,
|
||||||
|
AddrParseError = -32,
|
||||||
|
DisableMemoryLimitFailed = -33,
|
||||||
|
NotEnoughBytes = -34,
|
||||||
|
Utf8Error = -35,
|
||||||
|
InvalidArgument = -36,
|
||||||
|
UnknownErrorType = -37,
|
||||||
|
// FFI specific bindings
|
||||||
|
InvalidString = -999,
|
||||||
|
InvalidArg = -1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IdeviceError> for IdeviceErrorCode {
|
||||||
|
fn from(err: IdeviceError) -> Self {
|
||||||
|
match err {
|
||||||
|
IdeviceError::Socket(_) => IdeviceErrorCode::Socket,
|
||||||
|
IdeviceError::Ssl(_) => IdeviceErrorCode::Ssl,
|
||||||
|
IdeviceError::SslSetup(_) => IdeviceErrorCode::SslSetup,
|
||||||
|
IdeviceError::Plist(_) => IdeviceErrorCode::Plist,
|
||||||
|
IdeviceError::Utf8(_) => IdeviceErrorCode::Utf8,
|
||||||
|
IdeviceError::UnexpectedResponse => IdeviceErrorCode::UnexpectedResponse,
|
||||||
|
IdeviceError::GetProhibited => IdeviceErrorCode::GetProhibited,
|
||||||
|
IdeviceError::SessionInactive => IdeviceErrorCode::SessionInactive,
|
||||||
|
IdeviceError::InvalidHostID => IdeviceErrorCode::InvalidHostID,
|
||||||
|
IdeviceError::NoEstablishedConnection => IdeviceErrorCode::NoEstablishedConnection,
|
||||||
|
IdeviceError::HeartbeatSleepyTime => IdeviceErrorCode::HeartbeatSleepyTime,
|
||||||
|
IdeviceError::HeartbeatTimeout => IdeviceErrorCode::HeartbeatTimeout,
|
||||||
|
IdeviceError::NotFound => IdeviceErrorCode::NotFound,
|
||||||
|
IdeviceError::CdtunnelPacketTooShort => IdeviceErrorCode::CdtunnelPacketTooShort,
|
||||||
|
IdeviceError::CdtunnelPacketInvalidMagic => {
|
||||||
|
IdeviceErrorCode::CdtunnelPacketInvalidMagic
|
||||||
|
}
|
||||||
|
IdeviceError::PacketSizeMismatch => IdeviceErrorCode::PacketSizeMismatch,
|
||||||
|
IdeviceError::Json(_) => IdeviceErrorCode::Json,
|
||||||
|
IdeviceError::DeviceNotFound => IdeviceErrorCode::DeviceNotFound,
|
||||||
|
IdeviceError::DeviceLocked => IdeviceErrorCode::DeviceLocked,
|
||||||
|
IdeviceError::UsbConnectionRefused => IdeviceErrorCode::UsbConnectionRefused,
|
||||||
|
IdeviceError::UsbBadCommand => IdeviceErrorCode::UsbBadCommand,
|
||||||
|
IdeviceError::UsbBadDevice => IdeviceErrorCode::UsbBadDevice,
|
||||||
|
IdeviceError::UsbBadVersion => IdeviceErrorCode::UsbBadVersion,
|
||||||
|
IdeviceError::BadBuildManifest => IdeviceErrorCode::BadBuildManifest,
|
||||||
|
IdeviceError::ImageNotMounted => IdeviceErrorCode::ImageNotMounted,
|
||||||
|
IdeviceError::Reqwest(_) => IdeviceErrorCode::Reqwest,
|
||||||
|
IdeviceError::InternalError(_) => IdeviceErrorCode::InternalError,
|
||||||
|
IdeviceError::Xpc(_) => IdeviceErrorCode::Xpc,
|
||||||
|
IdeviceError::NsKeyedArchiveError(_) => IdeviceErrorCode::NsKeyedArchiveError,
|
||||||
|
IdeviceError::UnknownAuxValueType(_) => IdeviceErrorCode::UnknownAuxValueType,
|
||||||
|
IdeviceError::UnknownChannel(_) => IdeviceErrorCode::UnknownChannel,
|
||||||
|
IdeviceError::AddrParseError(_) => IdeviceErrorCode::AddrParseError,
|
||||||
|
IdeviceError::DisableMemoryLimitFailed => IdeviceErrorCode::DisableMemoryLimitFailed,
|
||||||
|
IdeviceError::NotEnoughBytes(_, _) => IdeviceErrorCode::NotEnoughBytes,
|
||||||
|
IdeviceError::Utf8Error => IdeviceErrorCode::Utf8Error,
|
||||||
|
IdeviceError::InvalidArgument => IdeviceErrorCode::InvalidArgument,
|
||||||
|
IdeviceError::UnknownErrorType(_) => IdeviceErrorCode::UnknownErrorType,
|
||||||
|
_ => IdeviceErrorCode::InternalError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
261
ffi/src/lib.rs
Normal file
261
ffi/src/lib.rs
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
mod errors;
|
||||||
|
pub mod logging;
|
||||||
|
mod pairing_file;
|
||||||
|
pub mod provider;
|
||||||
|
pub mod usbmuxd;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
|
pub use errors::*;
|
||||||
|
pub use pairing_file::*;
|
||||||
|
|
||||||
|
use idevice::{Idevice, IdeviceSocket};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::ffi::{CStr, CString, c_char};
|
||||||
|
use tokio::runtime::{self, Runtime};
|
||||||
|
|
||||||
|
static RUNTIME: Lazy<Runtime> = Lazy::new(|| {
|
||||||
|
runtime::Builder::new_multi_thread()
|
||||||
|
.enable_io()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const LOCKDOWN_PORT: u16 = 62078;
|
||||||
|
|
||||||
|
/// Opaque C-compatible handle to an Idevice connection
|
||||||
|
pub struct IdeviceHandle(pub Idevice);
|
||||||
|
pub struct IdeviceSocketHandle(IdeviceSocket);
|
||||||
|
|
||||||
|
// https://github.com/mozilla/cbindgen/issues/539
|
||||||
|
#[allow(non_camel_case_types, unused)]
|
||||||
|
struct sockaddr;
|
||||||
|
|
||||||
|
/// Creates a new Idevice connection
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`socket`] - Socket for communication with the device
|
||||||
|
/// * [`label`] - Label for the connection
|
||||||
|
/// * [`idevice`] - On success, will be set to point to a newly allocated Idevice handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An error code indicating success or failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `label` must be a valid null-terminated C string
|
||||||
|
/// `idevice` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_new(
|
||||||
|
socket: *mut IdeviceSocketHandle,
|
||||||
|
label: *const c_char,
|
||||||
|
idevice: *mut *mut IdeviceHandle,
|
||||||
|
) -> IdeviceErrorCode {
|
||||||
|
if socket.is_null() || label.is_null() || idevice.is_null() {
|
||||||
|
return IdeviceErrorCode::InvalidArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get socket ownership
|
||||||
|
let socket_box = unsafe { Box::from_raw(socket) };
|
||||||
|
|
||||||
|
// Convert C string to Rust string
|
||||||
|
let c_str = match unsafe { CStr::from_ptr(label).to_str() } {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return IdeviceErrorCode::InvalidString,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create new Idevice instance
|
||||||
|
let dev = Idevice::new((*socket_box).0, c_str);
|
||||||
|
let boxed = Box::new(IdeviceHandle(dev));
|
||||||
|
unsafe { *idevice = Box::into_raw(boxed) };
|
||||||
|
|
||||||
|
IdeviceErrorCode::IdeviceSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Idevice connection
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`addr`] - The socket address to connect to
|
||||||
|
/// * [`addr_len`] - Length of the socket
|
||||||
|
/// * [`label`] - Label for the connection
|
||||||
|
/// * [`idevice`] - On success, will be set to point to a newly allocated Idevice handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An error code indicating success or failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `addr` must be a valid sockaddr
|
||||||
|
/// `label` must be a valid null-terminated C string
|
||||||
|
/// `idevice` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_new_tcp_socket(
|
||||||
|
addr: *const libc::sockaddr,
|
||||||
|
addr_len: libc::socklen_t,
|
||||||
|
label: *const c_char,
|
||||||
|
idevice: *mut *mut IdeviceHandle,
|
||||||
|
) -> IdeviceErrorCode {
|
||||||
|
if addr.is_null() {
|
||||||
|
log::error!("socket addr null pointer");
|
||||||
|
return IdeviceErrorCode::InvalidArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert C string to Rust string
|
||||||
|
let label = match unsafe { CStr::from_ptr(label).to_str() } {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return IdeviceErrorCode::InvalidArg,
|
||||||
|
};
|
||||||
|
|
||||||
|
let addr = match util::c_socket_to_rust(addr, addr_len) {
|
||||||
|
Ok(a) => a,
|
||||||
|
Err(e) => return e,
|
||||||
|
};
|
||||||
|
|
||||||
|
let device: Result<idevice::Idevice, idevice::IdeviceError> = RUNTIME.block_on(async move {
|
||||||
|
Ok(idevice::Idevice::new(
|
||||||
|
Box::new(tokio::net::TcpStream::connect(addr).await?),
|
||||||
|
label,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
|
match device {
|
||||||
|
Ok(dev) => {
|
||||||
|
let boxed = Box::new(IdeviceHandle(dev));
|
||||||
|
unsafe { *idevice = Box::into_raw(boxed) };
|
||||||
|
IdeviceErrorCode::IdeviceSuccess
|
||||||
|
}
|
||||||
|
Err(e) => e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the device type
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`idevice`] - The Idevice handle
|
||||||
|
/// * [`device_type`] - On success, will be set to point to a newly allocated string containing the device type
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An error code indicating success or failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `idevice` must be a valid, non-null pointer to an Idevice handle
|
||||||
|
/// `device_type` must be a valid, non-null pointer to a location where the string pointer will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_get_type(
|
||||||
|
idevice: *mut IdeviceHandle,
|
||||||
|
device_type: *mut *mut c_char,
|
||||||
|
) -> IdeviceErrorCode {
|
||||||
|
if idevice.is_null() || device_type.is_null() {
|
||||||
|
return IdeviceErrorCode::InvalidArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Idevice reference
|
||||||
|
let dev = unsafe { &mut (*idevice).0 };
|
||||||
|
|
||||||
|
// Run the get_type method in the runtime
|
||||||
|
let result = RUNTIME.block_on(async { dev.get_type().await });
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(type_str) => match CString::new(type_str) {
|
||||||
|
Ok(c_string) => {
|
||||||
|
unsafe { *device_type = c_string.into_raw() };
|
||||||
|
IdeviceErrorCode::IdeviceSuccess
|
||||||
|
}
|
||||||
|
Err(_) => IdeviceErrorCode::InvalidString,
|
||||||
|
},
|
||||||
|
Err(e) => e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs RSD checkin
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`idevice`] - The Idevice handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An error code indicating success or failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `idevice` must be a valid, non-null pointer to an Idevice handle
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_rsd_checkin(idevice: *mut IdeviceHandle) -> IdeviceErrorCode {
|
||||||
|
if idevice.is_null() {
|
||||||
|
return IdeviceErrorCode::InvalidArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Idevice reference
|
||||||
|
let dev = unsafe { &mut (*idevice).0 };
|
||||||
|
|
||||||
|
// Run the rsd_checkin method in the runtime
|
||||||
|
let result = RUNTIME.block_on(async { dev.rsd_checkin().await });
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => IdeviceErrorCode::IdeviceSuccess,
|
||||||
|
Err(e) => e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts a TLS session
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`idevice`] - The Idevice handle
|
||||||
|
/// * [`pairing_file`] - The pairing file to use for TLS
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An error code indicating success or failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `idevice` must be a valid, non-null pointer to an Idevice handle
|
||||||
|
/// `pairing_file` must be a valid, non-null pointer to a pairing file handle
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_start_session(
|
||||||
|
idevice: *mut IdeviceHandle,
|
||||||
|
pairing_file: *const IdevicePairingFile,
|
||||||
|
) -> IdeviceErrorCode {
|
||||||
|
if idevice.is_null() || pairing_file.is_null() {
|
||||||
|
return IdeviceErrorCode::InvalidArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Idevice reference
|
||||||
|
let dev = unsafe { &mut (*idevice).0 };
|
||||||
|
|
||||||
|
// Get the pairing file reference
|
||||||
|
let pf = unsafe { &(*pairing_file).0 };
|
||||||
|
|
||||||
|
// Run the start_session method in the runtime
|
||||||
|
let result = RUNTIME.block_on(async { dev.start_session(pf).await });
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => IdeviceErrorCode::IdeviceSuccess,
|
||||||
|
Err(e) => e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees an Idevice handle
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`idevice`] - The Idevice handle to free
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `idevice` must be a valid pointer to an Idevice handle that was allocated by this library,
|
||||||
|
/// or NULL (in which case this function does nothing)
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_free(idevice: *mut IdeviceHandle) {
|
||||||
|
if !idevice.is_null() {
|
||||||
|
let _ = unsafe { Box::from_raw(idevice) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees a string allocated by this library
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`string`] - The string to free
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `string` must be a valid pointer to a string that was allocated by this library,
|
||||||
|
/// or NULL (in which case this function does nothing)
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_string_free(string: *mut c_char) {
|
||||||
|
if !string.is_null() {
|
||||||
|
let _ = unsafe { CString::from_raw(string) };
|
||||||
|
}
|
||||||
|
}
|
||||||
124
ffi/src/logging.rs
Normal file
124
ffi/src/logging.rs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ffi::{CString, c_char},
|
||||||
|
fs::File,
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::LevelFilter;
|
||||||
|
use simplelog::{
|
||||||
|
ColorChoice, CombinedLogger, Config, SharedLogger, TermLogger, TerminalMode, WriteLogger,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Initializes the logger
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`console_level`] - The level to log to the file
|
||||||
|
/// * [`file_level`] - The level to log to the file
|
||||||
|
/// * [`file_path`] - If not null, the file to write logs to
|
||||||
|
///
|
||||||
|
/// ## Log Level
|
||||||
|
/// 0. Disabled
|
||||||
|
/// 1. Error
|
||||||
|
/// 2. Warn
|
||||||
|
/// 3. Info
|
||||||
|
/// 4. Debug
|
||||||
|
/// 5. Trace
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// 0 for success, -1 if the file couldn't be created, -2 if a logger has been initialized, -3 for invalid path string
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Pass a valid CString for file_path. Pass valid log levels according to the enum
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn idevice_init_logger(
|
||||||
|
console_level: IdeviceLogLevel,
|
||||||
|
file_level: IdeviceLogLevel,
|
||||||
|
file_path: *mut c_char,
|
||||||
|
) -> IdeviceLoggerError {
|
||||||
|
let mut loggers: Vec<Box<dyn SharedLogger>> = Vec::new();
|
||||||
|
let level: LevelFilter = console_level.into();
|
||||||
|
loggers.push(TermLogger::new(
|
||||||
|
level,
|
||||||
|
Config::default(),
|
||||||
|
TerminalMode::Mixed,
|
||||||
|
ColorChoice::Auto,
|
||||||
|
));
|
||||||
|
|
||||||
|
if !file_path.is_null() {
|
||||||
|
let file_path = match unsafe { CString::from_raw(file_path) }.to_str() {
|
||||||
|
Ok(f) => f.to_string(),
|
||||||
|
Err(_) => {
|
||||||
|
return IdeviceLoggerError::InvalidPathString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let level: LevelFilter = file_level.into();
|
||||||
|
loggers.push(WriteLogger::new(
|
||||||
|
level,
|
||||||
|
Config::default(),
|
||||||
|
match File::create(file_path) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to create path: {e:?}");
|
||||||
|
return IdeviceLoggerError::FileError;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if CombinedLogger::init(loggers).is_err() {
|
||||||
|
IdeviceLoggerError::AlreadyInitialized
|
||||||
|
} else {
|
||||||
|
IdeviceLoggerError::Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum IdeviceLoggerError {
|
||||||
|
Success = 0,
|
||||||
|
FileError = -1,
|
||||||
|
AlreadyInitialized = -2,
|
||||||
|
InvalidPathString = -3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum IdeviceLogLevel {
|
||||||
|
Disabled = 0,
|
||||||
|
ErrorLevel = 1,
|
||||||
|
Warn = 2,
|
||||||
|
Info = 3,
|
||||||
|
Debug = 4,
|
||||||
|
Trace = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for IdeviceLogLevel {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
0 => Self::Disabled,
|
||||||
|
1 => Self::ErrorLevel,
|
||||||
|
2 => Self::Warn,
|
||||||
|
3 => Self::Info,
|
||||||
|
4 => Self::Debug,
|
||||||
|
5 => Self::Trace,
|
||||||
|
_ => {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IdeviceLogLevel> for LevelFilter {
|
||||||
|
fn from(value: IdeviceLogLevel) -> Self {
|
||||||
|
match value {
|
||||||
|
IdeviceLogLevel::Disabled => LevelFilter::Off,
|
||||||
|
IdeviceLogLevel::ErrorLevel => LevelFilter::Error,
|
||||||
|
IdeviceLogLevel::Warn => LevelFilter::Warn,
|
||||||
|
IdeviceLogLevel::Info => LevelFilter::Info,
|
||||||
|
IdeviceLogLevel::Debug => LevelFilter::Debug,
|
||||||
|
IdeviceLogLevel::Trace => LevelFilter::Trace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user