mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Remove cpp 17 features and implement Rust into CPP
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
#include <cstdint>
|
||||
#include <idevice++/bindings.hpp>
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/option.hpp>
|
||||
#include <idevice++/result.hpp>
|
||||
#include <vector>
|
||||
|
||||
struct IdeviceFfiError;
|
||||
@@ -31,16 +33,16 @@ class AdapterStream {
|
||||
|
||||
~AdapterStream() noexcept = default; // no auto-close; caller controls
|
||||
|
||||
AdapterStreamHandle* raw() const noexcept { return h_; }
|
||||
AdapterStreamHandle* raw() const noexcept { return h_; }
|
||||
|
||||
bool close(FfiError& err);
|
||||
bool send(const uint8_t* data, size_t len, FfiError& err);
|
||||
bool send(const std::vector<uint8_t>& buf, FfiError& err) {
|
||||
return send(buf.data(), buf.size(), err);
|
||||
Result<void, FfiError> close();
|
||||
Result<void, FfiError> send(const uint8_t* data, size_t len);
|
||||
Result<void, FfiError> send(const std::vector<uint8_t>& buf) {
|
||||
return send(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
// recv into caller-provided buffer (resizes to actual length)
|
||||
bool recv(std::vector<uint8_t>& out, FfiError& err, size_t max_hint = 2048);
|
||||
Result<std::vector<uint8_t>, FfiError> recv(size_t max_hint = 2048);
|
||||
|
||||
private:
|
||||
AdapterStreamHandle* h_{};
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <idevice++/readwrite.hpp>
|
||||
#include <idevice++/rsd.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -19,17 +18,17 @@ using AppServicePtr =
|
||||
std::unique_ptr<AppServiceHandle, FnDeleter<AppServiceHandle, app_service_free>>;
|
||||
|
||||
struct AppInfo {
|
||||
bool is_removable{};
|
||||
std::string name;
|
||||
bool is_first_party{};
|
||||
std::string path;
|
||||
std::string bundle_identifier;
|
||||
bool is_developer_app{};
|
||||
std::optional<std::string> bundle_version;
|
||||
bool is_internal{};
|
||||
bool is_hidden{};
|
||||
bool is_app_clip{};
|
||||
std::optional<std::string> version;
|
||||
bool is_removable{};
|
||||
std::string name;
|
||||
bool is_first_party{};
|
||||
std::string path;
|
||||
std::string bundle_identifier;
|
||||
bool is_developer_app{};
|
||||
Option<std::string> bundle_version;
|
||||
bool is_internal{};
|
||||
bool is_hidden{};
|
||||
bool is_app_clip{};
|
||||
Option<std::string> version;
|
||||
};
|
||||
|
||||
struct LaunchResponse {
|
||||
@@ -40,15 +39,15 @@ struct LaunchResponse {
|
||||
};
|
||||
|
||||
struct ProcessToken {
|
||||
uint32_t pid{};
|
||||
std::optional<std::string> executable_url;
|
||||
uint32_t pid{};
|
||||
Option<std::string> executable_url;
|
||||
};
|
||||
|
||||
struct SignalResponse {
|
||||
uint32_t pid{};
|
||||
std::optional<std::string> executable_url;
|
||||
uint64_t device_timestamp_ms{};
|
||||
uint32_t signal{};
|
||||
uint32_t pid{};
|
||||
Option<std::string> executable_url;
|
||||
uint64_t device_timestamp_ms{};
|
||||
uint32_t signal{};
|
||||
};
|
||||
|
||||
struct IconData {
|
||||
@@ -62,41 +61,34 @@ struct IconData {
|
||||
class AppService {
|
||||
public:
|
||||
// Factory: connect via RSD (borrows adapter & handshake)
|
||||
static std::optional<AppService>
|
||||
connect_rsd(Adapter& adapter, RsdHandshake& rsd, FfiError& err);
|
||||
static Result<AppService, FfiError> connect_rsd(Adapter& adapter, RsdHandshake& rsd);
|
||||
|
||||
// Factory: from socket Box<dyn ReadWrite> (consumes it).
|
||||
static std::optional<AppService> from_readwrite_ptr(ReadWriteOpaque* consumed, FfiError& err);
|
||||
static Result<AppService, FfiError> from_readwrite_ptr(ReadWriteOpaque* consumed);
|
||||
|
||||
// nice ergonomic overload: consume a C++ ReadWrite by releasing it
|
||||
static std::optional<AppService> from_readwrite(ReadWrite&& rw, FfiError& err);
|
||||
static Result<AppService, FfiError> from_readwrite(ReadWrite&& rw);
|
||||
|
||||
// API
|
||||
std::optional<std::vector<AppInfo>> list_apps(bool app_clips,
|
||||
bool removable,
|
||||
bool hidden,
|
||||
bool internal,
|
||||
bool default_apps,
|
||||
FfiError& err) const;
|
||||
Result<std::vector<AppInfo>, FfiError>
|
||||
list_apps(bool app_clips, bool removable, bool hidden, bool internal, bool default_apps) const;
|
||||
|
||||
std::optional<LaunchResponse> launch(const std::string& bundle_id,
|
||||
const std::vector<std::string>& argv,
|
||||
bool kill_existing,
|
||||
bool start_suspended,
|
||||
FfiError& err);
|
||||
Result<LaunchResponse, FfiError> launch(const std::string& bundle_id,
|
||||
const std::vector<std::string>& argv,
|
||||
bool kill_existing,
|
||||
bool start_suspended);
|
||||
|
||||
std::optional<std::vector<ProcessToken>> list_processes(FfiError& err) const;
|
||||
Result<std::vector<ProcessToken>, FfiError> list_processes() const;
|
||||
|
||||
bool uninstall(const std::string& bundle_id, FfiError& err);
|
||||
Result<void, FfiError> uninstall(const std::string& bundle_id);
|
||||
|
||||
std::optional<SignalResponse> send_signal(uint32_t pid, uint32_t signal, FfiError& err);
|
||||
Result<SignalResponse, FfiError> send_signal(uint32_t pid, uint32_t signal);
|
||||
|
||||
std::optional<IconData> fetch_icon(const std::string& bundle_id,
|
||||
float width,
|
||||
float height,
|
||||
float scale,
|
||||
bool allow_placeholder,
|
||||
FfiError& err);
|
||||
Result<IconData, FfiError> fetch_icon(const std::string& bundle_id,
|
||||
float width,
|
||||
float height,
|
||||
float scale,
|
||||
bool allow_placeholder);
|
||||
|
||||
// RAII / moves
|
||||
~AppService() noexcept = default;
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
#include <idevice++/bindings.hpp>
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/option.hpp>
|
||||
#include <idevice++/provider.hpp>
|
||||
#include <idevice++/readwrite.hpp>
|
||||
#include <idevice++/result.hpp>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
@@ -22,32 +24,33 @@ struct CoreClientParams {
|
||||
|
||||
class Adapter {
|
||||
public:
|
||||
~Adapter() noexcept = default;
|
||||
Adapter(Adapter&&) noexcept = default;
|
||||
Adapter& operator=(Adapter&&) noexcept = default;
|
||||
Adapter(const Adapter&) = delete;
|
||||
Adapter& operator=(const Adapter&) = delete;
|
||||
~Adapter() noexcept = default;
|
||||
Adapter(Adapter&&) noexcept = default;
|
||||
Adapter& operator=(Adapter&&) noexcept = default;
|
||||
Adapter(const Adapter&) = delete;
|
||||
Adapter& operator=(const Adapter&) = delete;
|
||||
|
||||
static Adapter adopt(AdapterHandle* h) noexcept { return Adapter(h); }
|
||||
AdapterHandle* raw() const noexcept { return handle_.get(); }
|
||||
static Adapter adopt(AdapterHandle* h) noexcept { return Adapter(h); }
|
||||
AdapterHandle* raw() const noexcept { return handle_.get(); }
|
||||
|
||||
// Enable PCAP
|
||||
bool pcap(const std::string& path, FfiError& err) {
|
||||
if (IdeviceFfiError* e = ::adapter_pcap(handle_.get(), path.c_str())) {
|
||||
err = FfiError(e);
|
||||
return false;
|
||||
Result<void, FfiError> pcap(const std::string& path) {
|
||||
FfiError e(::adapter_pcap(handle_.get(), path.c_str()));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
return true;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// Connect to a port, returns a ReadWrite stream (to be consumed by RSD/CoreDeviceProxy)
|
||||
std::optional<ReadWrite> connect(uint16_t port, FfiError& err) {
|
||||
// Connect to a port, returns a ReadWrite stream (to be consumed by
|
||||
// RSD/CoreDeviceProxy)
|
||||
Result<ReadWrite, FfiError> connect(uint16_t port) {
|
||||
ReadWriteOpaque* s = nullptr;
|
||||
if (IdeviceFfiError* e = ::adapter_connect(handle_.get(), port, &s)) {
|
||||
err = FfiError(e);
|
||||
return std::nullopt;
|
||||
FfiError e(::adapter_connect(handle_.get(), port, &s));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
return ReadWrite::adopt(s);
|
||||
return Ok(ReadWrite::adopt(s));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -58,28 +61,28 @@ class Adapter {
|
||||
class CoreDeviceProxy {
|
||||
public:
|
||||
// Factory: connect using a Provider (NOT consumed on success or error)
|
||||
static std::optional<CoreDeviceProxy> connect(Provider& provider, FfiError& err);
|
||||
static Result<CoreDeviceProxy, FfiError> connect(Provider& provider);
|
||||
|
||||
// Factory: from a socket; Rust consumes the socket regardless of result → we release before
|
||||
// call
|
||||
static std::optional<CoreDeviceProxy> from_socket(Idevice&& socket, FfiError& err);
|
||||
// Factory: from a socket; Rust consumes the socket regardless of result → we
|
||||
// release before call
|
||||
static Result<CoreDeviceProxy, FfiError> from_socket(Idevice&& socket);
|
||||
|
||||
// Send/recv
|
||||
bool send(const uint8_t* data, size_t len, FfiError& err);
|
||||
bool send(const std::vector<uint8_t>& buf, FfiError& err) {
|
||||
return send(buf.data(), buf.size(), err);
|
||||
Result<void, FfiError> send(const uint8_t* data, size_t len);
|
||||
Result<void, FfiError> send(const std::vector<uint8_t>& buf) {
|
||||
return send(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
// recv into a pre-sized buffer; resizes to actual bytes received
|
||||
bool recv(std::vector<uint8_t>& out, FfiError& err);
|
||||
Result<void, FfiError> recv(std::vector<uint8_t>& out);
|
||||
|
||||
// Handshake info
|
||||
std::optional<CoreClientParams> get_client_parameters(FfiError& err) const;
|
||||
std::optional<std::string> get_server_address(FfiError& err) const;
|
||||
std::optional<uint16_t> get_server_rsd_port(FfiError& err) const;
|
||||
Result<CoreClientParams, FfiError> get_client_parameters() const;
|
||||
Result<std::string, FfiError> get_server_address() const;
|
||||
Result<uint16_t, FfiError> get_server_rsd_port() const;
|
||||
|
||||
// Consuming creation of a TCP adapter: Rust consumes the proxy handle
|
||||
std::optional<Adapter> create_tcp_adapter(FfiError& err) &&;
|
||||
Result<Adapter, FfiError> create_tcp_adapter() &&;
|
||||
|
||||
// RAII / moves
|
||||
~CoreDeviceProxy() noexcept = default;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Bring in the global C ABI (all C structs/functions are global)
|
||||
#include <idevice++/core_device_proxy.hpp>
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/result.hpp>
|
||||
#include <idevice++/rsd.hpp>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
@@ -33,32 +33,33 @@ class DebugProxy {
|
||||
|
||||
~DebugProxy() { reset(); }
|
||||
|
||||
// Factory: connect over RSD (borrows adapter & handshake; does not consume them)
|
||||
static std::optional<DebugProxy>
|
||||
connect_rsd(Adapter& adapter, RsdHandshake& rsd, FfiError& err);
|
||||
// Factory: connect over RSD (borrows adapter & handshake; does not consume
|
||||
// them)
|
||||
static Result<DebugProxy, FfiError> connect_rsd(Adapter& adapter, RsdHandshake& rsd);
|
||||
|
||||
// Factory: consume a ReadWrite stream (fat pointer)
|
||||
static std::optional<DebugProxy> from_readwrite_ptr(::ReadWriteOpaque* consumed, FfiError& err);
|
||||
static Result<DebugProxy, FfiError> from_readwrite_ptr(::ReadWriteOpaque* consumed);
|
||||
|
||||
// Convenience: consume a C++ ReadWrite wrapper by releasing it into the ABI
|
||||
static std::optional<DebugProxy> from_readwrite(ReadWrite&& rw, FfiError& err);
|
||||
static Result<DebugProxy, FfiError> from_readwrite(ReadWrite&& rw);
|
||||
|
||||
// API
|
||||
std::optional<std::string>
|
||||
send_command(const std::string& name, const std::vector<std::string>& argv, FfiError& err);
|
||||
Result<Option<std::string>, FfiError> send_command(const std::string& name,
|
||||
const std::vector<std::string>& argv);
|
||||
|
||||
std::optional<std::string> read_response(FfiError& err);
|
||||
Result<Option<std::string>, FfiError> read_response();
|
||||
|
||||
bool send_raw(const std::vector<uint8_t>& data, FfiError& err);
|
||||
Result<void, FfiError> send_raw(const std::vector<uint8_t>& data);
|
||||
|
||||
// Reads up to `len` bytes; ABI returns a heap C string (we treat as bytes → string)
|
||||
std::optional<std::string> read(std::size_t len, FfiError& err);
|
||||
// Reads up to `len` bytes; ABI returns a heap C string (we treat as bytes →
|
||||
// string)
|
||||
Result<Option<std::string>, FfiError> read(std::size_t len);
|
||||
|
||||
// Sets argv, returns textual reply (OK/echo/etc)
|
||||
std::optional<std::string> set_argv(const std::vector<std::string>& argv, FfiError& err);
|
||||
Result<Option<std::string>, FfiError> set_argv(const std::vector<std::string>& argv);
|
||||
|
||||
bool send_ack(FfiError& err);
|
||||
bool send_nack(FfiError& err);
|
||||
Result<void, FfiError> send_ack();
|
||||
Result<void, FfiError> send_nack();
|
||||
|
||||
// No error object in ABI; immediate effect
|
||||
void set_ack_mode(bool enabled) { ::debug_proxy_set_ack_mode(handle_, enabled ? 1 : 0); }
|
||||
@@ -99,10 +100,9 @@ class DebugCommand {
|
||||
|
||||
~DebugCommand() { reset(); }
|
||||
|
||||
static std::optional<DebugCommand> make(const std::string& name,
|
||||
const std::vector<std::string>& argv);
|
||||
static Option<DebugCommand> make(const std::string& name, const std::vector<std::string>& argv);
|
||||
|
||||
::DebugserverCommandHandle* raw() const { return handle_; }
|
||||
::DebugserverCommandHandle* raw() const { return handle_; }
|
||||
|
||||
private:
|
||||
explicit DebugCommand(::DebugserverCommandHandle* h) : handle_(h) {}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -32,10 +31,11 @@ class SysdiagnoseStream {
|
||||
|
||||
~SysdiagnoseStream() { reset(); }
|
||||
|
||||
// Pull next chunk. Returns nullopt on end-of-stream. On error, returns nullopt and sets `err`.
|
||||
std::optional<std::vector<uint8_t>> next_chunk(FfiError& err);
|
||||
// Pull next chunk. Returns nullopt on end-of-stream. On error, returns
|
||||
// nullopt and sets `err`.
|
||||
Result<Option<std::vector<uint8_t>>, FfiError> next_chunk();
|
||||
|
||||
SysdiagnoseStreamHandle* raw() const { return h_; }
|
||||
SysdiagnoseStreamHandle* raw() const { return h_; }
|
||||
|
||||
private:
|
||||
friend class DiagnosticsService;
|
||||
@@ -78,21 +78,20 @@ class DiagnosticsService {
|
||||
~DiagnosticsService() { reset(); }
|
||||
|
||||
// Connect via RSD (borrows adapter & handshake; does not consume them)
|
||||
static std::optional<DiagnosticsService>
|
||||
connect_rsd(Adapter& adapter, RsdHandshake& rsd, FfiError& err);
|
||||
static Result<DiagnosticsService, FfiError> connect_rsd(Adapter& adapter, RsdHandshake& rsd);
|
||||
|
||||
// Create from a ReadWrite stream (consumes it)
|
||||
static std::optional<DiagnosticsService> from_stream_ptr(::ReadWriteOpaque* consumed,
|
||||
FfiError& err);
|
||||
static Result<DiagnosticsService, FfiError> from_stream_ptr(::ReadWriteOpaque* consumed);
|
||||
|
||||
static std::optional<DiagnosticsService> from_stream(ReadWrite&& rw, FfiError& err) {
|
||||
return from_stream_ptr(rw.release(), err);
|
||||
static Result<DiagnosticsService, FfiError> from_stream(ReadWrite&& rw) {
|
||||
return from_stream_ptr(rw.release());
|
||||
}
|
||||
|
||||
// Start sysdiagnose capture; on success returns filename, length and a byte stream
|
||||
std::optional<SysdiagnoseCapture> capture_sysdiagnose(bool dry_run, FfiError& err);
|
||||
// Start sysdiagnose capture; on success returns filename, length and a byte
|
||||
// stream
|
||||
Result<SysdiagnoseCapture, FfiError> capture_sysdiagnose(bool dry_run);
|
||||
|
||||
::DiagnosticsServiceHandle* raw() const { return h_; }
|
||||
::DiagnosticsServiceHandle* raw() const { return h_; }
|
||||
|
||||
private:
|
||||
explicit DiagnosticsService(::DiagnosticsServiceHandle* h) : h_(h) {}
|
||||
|
||||
@@ -15,7 +15,10 @@ class FfiError {
|
||||
FfiError(const IdeviceFfiError* err);
|
||||
FfiError();
|
||||
|
||||
explicit operator bool() const { return code != 0; }
|
||||
explicit operator bool() const { return code != 0; }
|
||||
|
||||
static FfiError NotConnected();
|
||||
static FfiError InvalidArgument();
|
||||
};
|
||||
} // namespace IdeviceFFI
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/pairing_file.hpp>
|
||||
#include <optional>
|
||||
#include <idevice++/result.hpp>
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
@@ -21,8 +21,9 @@ namespace IdeviceFFI {
|
||||
// Generic “bind a free function” deleter
|
||||
template <class T, void (*FreeFn)(T*)> struct FnDeleter {
|
||||
void operator()(T* p) const noexcept {
|
||||
if (p)
|
||||
if (p) {
|
||||
FreeFn(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,16 +31,15 @@ using IdevicePtr = std::unique_ptr<IdeviceHandle, FnDeleter<IdeviceHandle, idevi
|
||||
|
||||
class Idevice {
|
||||
public:
|
||||
static std::optional<Idevice>
|
||||
create(IdeviceSocketHandle* socket, const std::string& label, FfiError& err);
|
||||
static Result<Idevice, FfiError> create(IdeviceSocketHandle* socket, const std::string& label);
|
||||
|
||||
static std::optional<Idevice>
|
||||
create_tcp(const sockaddr* addr, socklen_t addr_len, const std::string& label, FfiError& err);
|
||||
static Result<Idevice, FfiError>
|
||||
create_tcp(const sockaddr* addr, socklen_t addr_len, const std::string& label);
|
||||
|
||||
// Methods
|
||||
std::optional<std::string> get_type(FfiError& err) const;
|
||||
bool rsd_checkin(FfiError& err);
|
||||
bool start_session(const PairingFile& pairing_file, FfiError& err);
|
||||
Result<std::string, FfiError> get_type() const;
|
||||
Result<void, FfiError> rsd_checkin();
|
||||
Result<void, FfiError> start_session(const PairingFile& pairing_file);
|
||||
|
||||
// Ownership/RAII
|
||||
~Idevice() noexcept = default;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#pragma once
|
||||
#include <idevice++/bindings.hpp>
|
||||
#include <idevice++/remote_server.hpp>
|
||||
#include <idevice++/result.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
@@ -14,10 +14,10 @@ using LocSimPtr = std::unique_ptr<LocationSimulationHandle,
|
||||
class LocationSimulation {
|
||||
public:
|
||||
// Factory: borrows the RemoteServer; not consumed
|
||||
static std::optional<LocationSimulation> create(RemoteServer& server, FfiError& err);
|
||||
static Result<LocationSimulation, FfiError> create(RemoteServer& server);
|
||||
|
||||
bool clear(FfiError& err);
|
||||
bool set(double latitude, double longitude, FfiError& err);
|
||||
Result<void, FfiError> clear();
|
||||
Result<void, FfiError> set(double latitude, double longitude);
|
||||
|
||||
~LocationSimulation() noexcept = default;
|
||||
LocationSimulation(LocationSimulation&&) noexcept = default;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/provider.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
@@ -16,16 +15,15 @@ using LockdownPtr =
|
||||
class Lockdown {
|
||||
public:
|
||||
// Factory: connect via Provider
|
||||
static std::optional<Lockdown> connect(Provider& provider, FfiError& err);
|
||||
static Result<Lockdown, FfiError> connect(Provider& provider);
|
||||
|
||||
// Factory: wrap an existing Idevice socket (consumes it on success)
|
||||
static std::optional<Lockdown> from_socket(Idevice&& socket, FfiError& err);
|
||||
static Result<Lockdown, FfiError> from_socket(Idevice&& socket);
|
||||
|
||||
// Ops
|
||||
bool start_session(const PairingFile& pf, FfiError& err);
|
||||
std::optional<std::pair<uint16_t, bool>> start_service(const std::string& identifier,
|
||||
FfiError& err);
|
||||
std::optional<plist_t> get_value(const char* key, const char* domain, FfiError& err);
|
||||
Result<void, FfiError> start_session(const PairingFile& pf);
|
||||
Result<std::pair<uint16_t, bool>, FfiError> start_service(const std::string& identifier);
|
||||
Result<plist_t, FfiError> get_value(const char* key, const char* domain);
|
||||
|
||||
// RAII / moves
|
||||
~Lockdown() noexcept = default;
|
||||
|
||||
184
cpp/include/idevice++/option.hpp
Normal file
184
cpp/include/idevice++/option.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// So here's the thing, std::optional and friends weren't added until C++17.
|
||||
// Some consumers of this codebase aren't on C++17 yet, so this won't work.
|
||||
// Plus, as a professional Rust evangelist, it's my duty to place as many Rust
|
||||
// idioms into other languages as possible to give everyone a taste of greatness.
|
||||
// Required error handling is correct error handling. And they called me a mad man.
|
||||
|
||||
// Heavily influced from https://github.com/oktal/result, thank you
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
struct none_t {};
|
||||
constexpr none_t None{};
|
||||
|
||||
template <typename T> class Option {
|
||||
bool has_;
|
||||
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
|
||||
|
||||
T* ptr() { return reinterpret_cast<T*>(&storage_); }
|
||||
const T* ptr() const { return reinterpret_cast<const T*>(&storage_); }
|
||||
|
||||
public:
|
||||
// None
|
||||
Option() noexcept : has_(false) {}
|
||||
Option(none_t) noexcept : has_(false) {}
|
||||
|
||||
// Some
|
||||
Option(const T& v) : has_(true) { ::new (ptr()) T(v); }
|
||||
Option(T&& v) : has_(true) { ::new (ptr()) T(std::move(v)); }
|
||||
|
||||
// Copy / move
|
||||
Option(const Option& o) : has_(o.has_) {
|
||||
if (has_) {
|
||||
::new (ptr()) T(*o.ptr());
|
||||
}
|
||||
}
|
||||
Option(Option&& o) noexcept(std::is_nothrow_move_constructible<T>::value) : has_(o.has_) {
|
||||
if (has_) {
|
||||
::new (ptr()) T(std::move(*o.ptr()));
|
||||
o.reset();
|
||||
}
|
||||
}
|
||||
|
||||
Option& operator=(Option o) noexcept(std::is_nothrow_move_constructible<T>::value
|
||||
&& std::is_nothrow_move_assignable<T>::value) {
|
||||
swap(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Option() { reset(); }
|
||||
|
||||
void reset() noexcept {
|
||||
if (has_) {
|
||||
ptr()->~T();
|
||||
has_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(Option& other) noexcept(std::is_nothrow_move_constructible<T>::value) {
|
||||
if (has_ && other.has_) {
|
||||
using std::swap;
|
||||
swap(*ptr(), *other.ptr());
|
||||
} else if (has_ && !other.has_) {
|
||||
::new (other.ptr()) T(std::move(*ptr()));
|
||||
other.has_ = true;
|
||||
reset();
|
||||
} else if (!has_ && other.has_) {
|
||||
::new (ptr()) T(std::move(*other.ptr()));
|
||||
has_ = true;
|
||||
other.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// State
|
||||
bool is_some() const noexcept { return has_; }
|
||||
bool is_none() const noexcept { return !has_; }
|
||||
|
||||
// Unwraps (ref-qualified)
|
||||
T& unwrap() & {
|
||||
if (!has_) {
|
||||
throw std::runtime_error("unwrap on None");
|
||||
}
|
||||
return *ptr();
|
||||
}
|
||||
const T& unwrap() const& {
|
||||
if (!has_) {
|
||||
throw std::runtime_error("unwrap on None");
|
||||
}
|
||||
return *ptr();
|
||||
}
|
||||
T unwrap() && {
|
||||
if (!has_) {
|
||||
throw std::runtime_error("unwrap on None");
|
||||
}
|
||||
T tmp = std::move(*ptr());
|
||||
reset();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// unwrap_or / unwrap_or_else
|
||||
T unwrap_or(T default_value) const& { return has_ ? *ptr() : std::move(default_value); }
|
||||
T unwrap_or(T default_value) && { return has_ ? std::move(*ptr()) : std::move(default_value); }
|
||||
|
||||
template <typename F> T unwrap_or_else(F&& f) const& {
|
||||
return has_ ? *ptr() : static_cast<T>(f());
|
||||
}
|
||||
template <typename F> T unwrap_or_else(F&& f) && {
|
||||
return has_ ? std::move(*ptr()) : static_cast<T>(f());
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename F>
|
||||
auto map(F&& f) const -> Option<typename std::decay<decltype(f(*ptr()))>::type> {
|
||||
using U = typename std::decay<decltype(f(*ptr()))>::type;
|
||||
if (has_) {
|
||||
return Option<U>(f(*ptr()));
|
||||
}
|
||||
return Option<U>(None);
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers
|
||||
template <typename T> inline Option<typename std::decay<T>::type> Some(T&& v) {
|
||||
return Option<typename std::decay<T>::type>(std::forward<T>(v));
|
||||
}
|
||||
inline Option<void> Some() = delete; // no Option<void>
|
||||
|
||||
// template <typename T> inline Option<T> None() {
|
||||
// return Option<T>(none);
|
||||
// } // still needs T specified
|
||||
|
||||
// Prefer this at call sites (lets return-type drive the type):
|
||||
// return none;
|
||||
|
||||
#define match_option(opt, SOME, NONE) \
|
||||
if ((opt).is_some()) { \
|
||||
auto&& SOME = (opt).unwrap();
|
||||
#define or_else \
|
||||
} \
|
||||
else { \
|
||||
NONE; \
|
||||
}
|
||||
|
||||
// --- Option helpers: if_let_some / if_let_some_move / if_let_none ---
|
||||
|
||||
#define _opt_concat(a, b) a##b
|
||||
#define _opt_unique(base) _opt_concat(base, __LINE__)
|
||||
|
||||
/* Bind a reference to the contained value if Some(...) */
|
||||
#define if_let_some(expr, name, block) \
|
||||
do { \
|
||||
auto _opt_unique(_opt_) = (expr); \
|
||||
if (_opt_unique(_opt_).is_some()) { \
|
||||
auto&& name = _opt_unique(_opt_).unwrap(); \
|
||||
block \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Move the contained value out (consumes the Option) if Some(...) */
|
||||
#define if_let_some_move(expr, name, block) \
|
||||
do { \
|
||||
auto _opt_unique(_opt_) = (expr); \
|
||||
if (_opt_unique(_opt_).is_some()) { \
|
||||
auto name = std::move(_opt_unique(_opt_)).unwrap(); \
|
||||
block \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Run a block if the option is None */
|
||||
#define if_let_none(expr, block) \
|
||||
do { \
|
||||
auto _opt_unique(_opt_) = (expr); \
|
||||
if (_opt_unique(_opt_).is_none()) { \
|
||||
block \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
} // namespace IdeviceFFI
|
||||
@@ -6,10 +6,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <optional>
|
||||
#include <idevice++/result.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
struct PairingFileDeleter {
|
||||
@@ -20,8 +20,8 @@ using PairingFilePtr = std::unique_ptr<IdevicePairingFile, PairingFileDeleter>;
|
||||
|
||||
class PairingFile {
|
||||
public:
|
||||
static std::optional<PairingFile> read(const std::string& path, FfiError& err);
|
||||
static std::optional<PairingFile> from_bytes(const uint8_t* data, size_t size, FfiError& err);
|
||||
static Result<PairingFile, FfiError> read(const std::string& path);
|
||||
static Result<PairingFile, FfiError> from_bytes(const uint8_t* data, size_t size);
|
||||
|
||||
~PairingFile() noexcept = default; // unique_ptr handles destruction
|
||||
|
||||
@@ -29,9 +29,9 @@ class PairingFile {
|
||||
PairingFile& operator=(const PairingFile&) = delete;
|
||||
|
||||
PairingFile(PairingFile&&) noexcept = default; // move is correct by default
|
||||
PairingFile& operator=(PairingFile&&) noexcept = default;
|
||||
PairingFile& operator=(PairingFile&&) noexcept = default;
|
||||
|
||||
std::optional<std::vector<uint8_t>> serialize(FfiError& err) const;
|
||||
Result<std::vector<uint8_t>, FfiError> serialize() const;
|
||||
|
||||
explicit PairingFile(IdevicePairingFile* ptr) noexcept : ptr_(ptr) {}
|
||||
IdevicePairingFile* raw() const noexcept { return ptr_.get(); }
|
||||
|
||||
@@ -5,43 +5,41 @@
|
||||
#include <idevice++/bindings.hpp>
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/usbmuxd.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
class FfiError;
|
||||
class PairingFile; // has: IdevicePairingFile* raw() const; void release_on_success();
|
||||
class UsbmuxdAddr; // has: UsbmuxdAddrHandle* raw() const; void release_on_success();
|
||||
class PairingFile; // has: IdevicePairingFile* raw() const; void
|
||||
// release_on_success();
|
||||
class UsbmuxdAddr; // has: UsbmuxdAddrHandle* raw() const; void
|
||||
// release_on_success();
|
||||
|
||||
using ProviderPtr =
|
||||
std::unique_ptr<IdeviceProviderHandle, FnDeleter<IdeviceProviderHandle, idevice_provider_free>>;
|
||||
|
||||
class Provider {
|
||||
public:
|
||||
static std::optional<Provider> tcp_new(const idevice_sockaddr* ip,
|
||||
PairingFile&& pairing,
|
||||
const std::string& label,
|
||||
FfiError& err);
|
||||
static Result<Provider, FfiError>
|
||||
tcp_new(const idevice_sockaddr* ip, PairingFile&& pairing, const std::string& label);
|
||||
|
||||
static std::optional<Provider> usbmuxd_new(UsbmuxdAddr&& addr,
|
||||
uint32_t tag,
|
||||
const std::string& udid,
|
||||
uint32_t device_id,
|
||||
const std::string& label,
|
||||
FfiError& err);
|
||||
static Result<Provider, FfiError> usbmuxd_new(UsbmuxdAddr&& addr,
|
||||
uint32_t tag,
|
||||
const std::string& udid,
|
||||
uint32_t device_id,
|
||||
const std::string& label);
|
||||
|
||||
~Provider() noexcept = default;
|
||||
Provider(Provider&&) noexcept = default;
|
||||
Provider& operator=(Provider&&) noexcept = default;
|
||||
Provider(const Provider&) = delete;
|
||||
Provider& operator=(const Provider&) = delete;
|
||||
~Provider() noexcept = default;
|
||||
Provider(Provider&&) noexcept = default;
|
||||
Provider& operator=(Provider&&) noexcept = default;
|
||||
Provider(const Provider&) = delete;
|
||||
Provider& operator=(const Provider&) = delete;
|
||||
|
||||
std::optional<PairingFile> get_pairing_file(FfiError& err);
|
||||
Result<PairingFile, FfiError> get_pairing_file();
|
||||
|
||||
IdeviceProviderHandle* raw() const noexcept { return handle_.get(); }
|
||||
static Provider adopt(IdeviceProviderHandle* h) noexcept { return Provider(h); }
|
||||
IdeviceProviderHandle* release() noexcept { return handle_.release(); }
|
||||
IdeviceProviderHandle* raw() const noexcept { return handle_.get(); }
|
||||
static Provider adopt(IdeviceProviderHandle* h) noexcept { return Provider(h); }
|
||||
IdeviceProviderHandle* release() noexcept { return handle_.release(); }
|
||||
|
||||
private:
|
||||
explicit Provider(IdeviceProviderHandle* h) noexcept : handle_(h) {}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <idevice++/readwrite.hpp>
|
||||
#include <idevice++/rsd.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
@@ -19,11 +18,10 @@ using RemoteServerPtr =
|
||||
class RemoteServer {
|
||||
public:
|
||||
// Factory: consumes the ReadWrite stream regardless of result
|
||||
static std::optional<RemoteServer> from_socket(ReadWrite&& rw, FfiError& err);
|
||||
static Result<RemoteServer, FfiError> from_socket(ReadWrite&& rw);
|
||||
|
||||
// Factory: borrows adapter + handshake (neither is consumed)
|
||||
static std::optional<RemoteServer>
|
||||
connect_rsd(Adapter& adapter, RsdHandshake& rsd, FfiError& err);
|
||||
static Result<RemoteServer, FfiError> connect_rsd(Adapter& adapter, RsdHandshake& rsd);
|
||||
|
||||
// RAII / moves
|
||||
~RemoteServer() noexcept = default;
|
||||
|
||||
231
cpp/include/idevice++/result.hpp
Normal file
231
cpp/include/idevice++/result.hpp
Normal file
@@ -0,0 +1,231 @@
|
||||
// Jackson Coxson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
namespace types {
|
||||
template <typename T> struct Ok {
|
||||
T val;
|
||||
|
||||
Ok(const T& val) : val(val) {}
|
||||
Ok(T&& val) : val(std::move(val)) {}
|
||||
};
|
||||
|
||||
template <> struct Ok<void> {};
|
||||
|
||||
template <typename E> struct Err {
|
||||
E val;
|
||||
|
||||
Err(const E& val) : val(val) {}
|
||||
Err(E&& val) : val(std::move(val)) {}
|
||||
};
|
||||
} // namespace types
|
||||
|
||||
template <typename T> inline types::Ok<typename std::decay<T>::type> Ok(T&& val) {
|
||||
return types::Ok<typename std::decay<T>::type>(std::forward<T>(val));
|
||||
}
|
||||
|
||||
inline types::Ok<void> Ok() {
|
||||
return types::Ok<void>();
|
||||
}
|
||||
|
||||
template <typename E> inline types::Err<typename std::decay<E>::type> Err(E&& val) {
|
||||
return types::Err<typename std::decay<E>::type>(std::forward<E>(val));
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Result<T, E>
|
||||
// =======================
|
||||
template <typename T, typename E> class Result {
|
||||
bool is_ok_;
|
||||
union {
|
||||
T ok_value_;
|
||||
E err_value_;
|
||||
};
|
||||
|
||||
public:
|
||||
Result(types::Ok<T> ok_val) : is_ok_(true), ok_value_(std::move(ok_val.val)) {}
|
||||
Result(types::Err<E> err_val) : is_ok_(false), err_value_(std::move(err_val.val)) {}
|
||||
|
||||
Result(const Result& other) : is_ok_(other.is_ok_) {
|
||||
if (is_ok_) {
|
||||
new (&ok_value_) T(other.ok_value_);
|
||||
} else {
|
||||
new (&err_value_) E(other.err_value_);
|
||||
}
|
||||
}
|
||||
|
||||
Result(Result&& other) noexcept : is_ok_(other.is_ok_) {
|
||||
if (is_ok_) {
|
||||
new (&ok_value_) T(std::move(other.ok_value_));
|
||||
} else {
|
||||
new (&err_value_) E(std::move(other.err_value_));
|
||||
}
|
||||
}
|
||||
|
||||
~Result() {
|
||||
if (is_ok_) {
|
||||
ok_value_.~T();
|
||||
} else {
|
||||
err_value_.~E();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_ok() const { return is_ok_; }
|
||||
bool is_err() const { return !is_ok_; }
|
||||
|
||||
// lvalue (mutable)
|
||||
T& unwrap() & {
|
||||
if (!is_ok_) {
|
||||
std::fprintf(stderr, "unwrap on Err\n");
|
||||
std::terminate();
|
||||
}
|
||||
return ok_value_;
|
||||
}
|
||||
|
||||
// lvalue (const)
|
||||
const T& unwrap() const& {
|
||||
if (!is_ok_) {
|
||||
std::fprintf(stderr, "unwrap on Err\n");
|
||||
std::terminate();
|
||||
}
|
||||
return ok_value_;
|
||||
}
|
||||
|
||||
// rvalue (consume/move)
|
||||
T unwrap() && {
|
||||
if (!is_ok_) {
|
||||
std::fprintf(stderr, "unwrap on Err\n");
|
||||
std::terminate();
|
||||
}
|
||||
return std::move(ok_value_);
|
||||
}
|
||||
|
||||
E& unwrap_err() & {
|
||||
if (is_ok_) {
|
||||
std::fprintf(stderr, "unwrap_err on Ok\n");
|
||||
std::terminate();
|
||||
}
|
||||
return err_value_;
|
||||
}
|
||||
|
||||
const E& unwrap_err() const& {
|
||||
if (is_ok_) {
|
||||
std::fprintf(stderr, "unwrap_err on Ok\n");
|
||||
std::terminate();
|
||||
}
|
||||
return err_value_;
|
||||
}
|
||||
|
||||
E unwrap_err() && {
|
||||
if (is_ok_) {
|
||||
std::fprintf(stderr, "unwrap_err on Ok\n");
|
||||
std::terminate();
|
||||
}
|
||||
return std::move(err_value_);
|
||||
}
|
||||
|
||||
T unwrap_or(T&& default_value) const { return is_ok_ ? ok_value_ : std::move(default_value); }
|
||||
|
||||
template <typename F> T unwrap_or_else(F&& f) & {
|
||||
return is_ok_ ? ok_value_ : static_cast<T>(f(err_value_));
|
||||
}
|
||||
|
||||
// const lvalue: returns T by copy
|
||||
template <typename F> T unwrap_or_else(F&& f) const& {
|
||||
return is_ok_ ? ok_value_ : static_cast<T>(f(err_value_));
|
||||
}
|
||||
|
||||
// rvalue: moves Ok(T) out; on Err(E), allow the handler to consume/move E
|
||||
template <typename F> T unwrap_or_else(F&& f) && {
|
||||
if (is_ok_) {
|
||||
return std::move(ok_value_);
|
||||
}
|
||||
return static_cast<T>(std::forward<F>(f)(std::move(err_value_)));
|
||||
}
|
||||
};
|
||||
|
||||
// Result<void, E> specialization
|
||||
|
||||
template <typename E> class Result<void, E> {
|
||||
bool is_ok_;
|
||||
union {
|
||||
char dummy_;
|
||||
E err_value_;
|
||||
};
|
||||
|
||||
public:
|
||||
Result(types::Ok<void>) : is_ok_(true), dummy_() {}
|
||||
Result(types::Err<E> err_val) : is_ok_(false), err_value_(std::move(err_val.val)) {}
|
||||
|
||||
Result(const Result& other) : is_ok_(other.is_ok_) {
|
||||
if (!is_ok_) {
|
||||
new (&err_value_) E(other.err_value_);
|
||||
}
|
||||
}
|
||||
|
||||
Result(Result&& other) noexcept : is_ok_(other.is_ok_) {
|
||||
if (!is_ok_) {
|
||||
new (&err_value_) E(std::move(other.err_value_));
|
||||
}
|
||||
}
|
||||
|
||||
~Result() {
|
||||
if (!is_ok_) {
|
||||
err_value_.~E();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_ok() const { return is_ok_; }
|
||||
bool is_err() const { return !is_ok_; }
|
||||
|
||||
void unwrap() const {
|
||||
if (!is_ok_) {
|
||||
std::fprintf(stderr, "Attempted to unwrap an error Result<void, E>\n");
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
const E& unwrap_err() const {
|
||||
if (is_ok_) {
|
||||
std::fprintf(stderr, "Attempted to unwrap_err on an ok Result<void, E>\n");
|
||||
std::terminate();
|
||||
}
|
||||
return err_value_;
|
||||
}
|
||||
|
||||
E& unwrap_err() {
|
||||
if (is_ok_) {
|
||||
std::fprintf(stderr, "Attempted to unwrap_err on an ok Result<void, E>\n");
|
||||
std::terminate();
|
||||
}
|
||||
return err_value_;
|
||||
}
|
||||
};
|
||||
|
||||
#define match_result(res, ok_name, ok_block, err_name, err_block) \
|
||||
if ((res).is_ok()) { \
|
||||
auto&& ok_name = (res).unwrap(); \
|
||||
ok_block \
|
||||
} else { \
|
||||
auto&& err_name = (res).unwrap_err(); \
|
||||
err_block \
|
||||
}
|
||||
|
||||
#define if_let_err(res, name, block) \
|
||||
if ((res).is_err()) { \
|
||||
auto&& name = (res).unwrap_err(); \
|
||||
block \
|
||||
}
|
||||
|
||||
#define if_let_ok(res, name, block) \
|
||||
if ((res).is_ok()) { \
|
||||
auto&& name = (res).unwrap(); \
|
||||
block \
|
||||
}
|
||||
} // namespace IdeviceFFI
|
||||
@@ -25,16 +25,16 @@ using RsdPtr =
|
||||
class RsdHandshake {
|
||||
public:
|
||||
// Factory: consumes the ReadWrite socket regardless of result
|
||||
static std::optional<RsdHandshake> from_socket(ReadWrite&& rw, FfiError& err);
|
||||
static Result<RsdHandshake, FfiError> from_socket(ReadWrite&& rw);
|
||||
|
||||
// Basic info
|
||||
std::optional<size_t> protocol_version(FfiError& err) const;
|
||||
std::optional<std::string> uuid(FfiError& err) const;
|
||||
Result<size_t, FfiError> protocol_version() const;
|
||||
Result<std::string, FfiError> uuid() const;
|
||||
|
||||
// Services
|
||||
std::optional<std::vector<RsdService>> services(FfiError& err) const;
|
||||
std::optional<bool> service_available(const std::string& name, FfiError& err) const;
|
||||
std::optional<RsdService> service_info(const std::string& name, FfiError& err) const;
|
||||
Result<std::vector<RsdService>, FfiError> services() const;
|
||||
Result<bool, FfiError> service_available(const std::string& name) const;
|
||||
Result<RsdService, FfiError> service_info(const std::string& name) const;
|
||||
|
||||
// RAII / moves
|
||||
~RsdHandshake() noexcept = default;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <idevice++/core_device_proxy.hpp>
|
||||
@@ -12,7 +11,8 @@
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
// ---------------- OwnedBuffer: RAII for zero-copy read buffers ----------------
|
||||
// ---------------- OwnedBuffer: RAII for zero-copy read buffers
|
||||
// ----------------
|
||||
class OwnedBuffer {
|
||||
public:
|
||||
OwnedBuffer() noexcept : p_(nullptr), n_(0) {}
|
||||
@@ -117,7 +117,8 @@ class TcpObjectStackEater {
|
||||
~TcpObjectStackEater() { reset(); }
|
||||
|
||||
// Blocks until a packet is available. On success, 'out' adopts the buffer
|
||||
// and you must keep 'out' alive until done (RAII frees via idevice_data_free).
|
||||
// and you must keep 'out' alive until done (RAII frees via
|
||||
// idevice_data_free).
|
||||
bool read(OwnedBuffer& out, FfiError& err) const;
|
||||
|
||||
::TcpEatObject* raw() const { return h_; }
|
||||
@@ -139,34 +140,34 @@ class TcpObjectStackEater {
|
||||
// ---------------- Stack builder: returns feeder + eater + adapter ------------
|
||||
class TcpObjectStack {
|
||||
public:
|
||||
TcpObjectStack() = default;
|
||||
TcpObjectStack(const TcpObjectStack&) = delete; // no sharing
|
||||
TcpObjectStack& operator=(const TcpObjectStack&) = delete;
|
||||
TcpObjectStack(TcpObjectStack&&) noexcept = default; // movable
|
||||
TcpObjectStack& operator=(TcpObjectStack&&) noexcept = default;
|
||||
TcpObjectStack() = default;
|
||||
TcpObjectStack(const TcpObjectStack&) = delete; // no sharing
|
||||
TcpObjectStack& operator=(const TcpObjectStack&) = delete;
|
||||
TcpObjectStack(TcpObjectStack&&) noexcept = default; // movable
|
||||
TcpObjectStack& operator=(TcpObjectStack&&) noexcept = default;
|
||||
|
||||
// Build the stack (dual-handle). Name kept to minimize churn.
|
||||
static std::optional<TcpObjectStack>
|
||||
create(const std::string& our_ip, const std::string& their_ip, FfiError& err);
|
||||
static Result<TcpObjectStack, FfiError> create(const std::string& our_ip,
|
||||
const std::string& their_ip);
|
||||
|
||||
TcpObjectStackFeeder& feeder();
|
||||
const TcpObjectStackFeeder& feeder() const;
|
||||
TcpObjectStackFeeder& feeder();
|
||||
const TcpObjectStackFeeder& feeder() const;
|
||||
|
||||
TcpObjectStackEater& eater();
|
||||
const TcpObjectStackEater& eater() const;
|
||||
TcpObjectStackEater& eater();
|
||||
const TcpObjectStackEater& eater() const;
|
||||
|
||||
Adapter& adapter();
|
||||
const Adapter& adapter() const;
|
||||
Adapter& adapter();
|
||||
const Adapter& adapter() const;
|
||||
|
||||
std::optional<TcpObjectStackFeeder> release_feeder(); // nullptr inside wrapper after call
|
||||
std::optional<TcpObjectStackEater> release_eater(); // nullptr inside wrapper after call
|
||||
std::optional<Adapter> release_adapter();
|
||||
Option<TcpObjectStackFeeder> release_feeder(); // nullptr inside wrapper after call
|
||||
Option<TcpObjectStackEater> release_eater(); // nullptr inside wrapper after call
|
||||
Option<Adapter> release_adapter();
|
||||
|
||||
private:
|
||||
struct Impl {
|
||||
TcpObjectStackFeeder feeder;
|
||||
TcpObjectStackEater eater;
|
||||
std::optional<Adapter> adapter;
|
||||
TcpObjectStackFeeder feeder;
|
||||
TcpObjectStackEater eater;
|
||||
Option<Adapter> adapter;
|
||||
};
|
||||
// Unique ownership so there’s a single point of truth to release from
|
||||
std::unique_ptr<Impl> impl_;
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <idevice++/idevice.hpp>
|
||||
#include <idevice++/option.hpp>
|
||||
#include <idevice++/pairing_file.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -29,10 +29,9 @@ using ConnectionPtr =
|
||||
|
||||
class UsbmuxdAddr {
|
||||
public:
|
||||
static std::optional<UsbmuxdAddr>
|
||||
tcp_new(const sockaddr* addr, socklen_t addr_len, FfiError& err);
|
||||
static Result<UsbmuxdAddr, FfiError> tcp_new(const sockaddr* addr, socklen_t addr_len);
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
static std::optional<UsbmuxdAddr> unix_new(const std::string& path, FfiError& err);
|
||||
static Result<UsbmuxdAddr, FfiError> unix_new(const std::string& path);
|
||||
#endif
|
||||
static UsbmuxdAddr default_new();
|
||||
|
||||
@@ -66,19 +65,19 @@ class UsbmuxdConnectionType {
|
||||
|
||||
class UsbmuxdDevice {
|
||||
public:
|
||||
~UsbmuxdDevice() noexcept = default;
|
||||
UsbmuxdDevice(UsbmuxdDevice&&) noexcept = default;
|
||||
UsbmuxdDevice& operator=(UsbmuxdDevice&&) noexcept = default;
|
||||
UsbmuxdDevice(const UsbmuxdDevice&) = delete;
|
||||
UsbmuxdDevice& operator=(const UsbmuxdDevice&) = delete;
|
||||
~UsbmuxdDevice() noexcept = default;
|
||||
UsbmuxdDevice(UsbmuxdDevice&&) noexcept = default;
|
||||
UsbmuxdDevice& operator=(UsbmuxdDevice&&) noexcept = default;
|
||||
UsbmuxdDevice(const UsbmuxdDevice&) = delete;
|
||||
UsbmuxdDevice& operator=(const UsbmuxdDevice&) = delete;
|
||||
|
||||
static UsbmuxdDevice adopt(UsbmuxdDeviceHandle* h) noexcept { return UsbmuxdDevice(h); }
|
||||
static UsbmuxdDevice adopt(UsbmuxdDeviceHandle* h) noexcept { return UsbmuxdDevice(h); }
|
||||
|
||||
UsbmuxdDeviceHandle* raw() const noexcept { return handle_.get(); }
|
||||
UsbmuxdDeviceHandle* raw() const noexcept { return handle_.get(); }
|
||||
|
||||
std::optional<std::string> get_udid() const;
|
||||
std::optional<uint32_t> get_id() const;
|
||||
std::optional<UsbmuxdConnectionType> get_connection_type() const;
|
||||
Option<std::string> get_udid() const;
|
||||
Option<uint32_t> get_id() const;
|
||||
Option<UsbmuxdConnectionType> get_connection_type() const;
|
||||
|
||||
private:
|
||||
explicit UsbmuxdDevice(UsbmuxdDeviceHandle* h) noexcept : handle_(h) {}
|
||||
@@ -91,30 +90,28 @@ class PairingFile;
|
||||
|
||||
class UsbmuxdConnection {
|
||||
public:
|
||||
static std::optional<UsbmuxdConnection>
|
||||
tcp_new(const idevice_sockaddr* addr, idevice_socklen_t addr_len, uint32_t tag, FfiError& err);
|
||||
static Result<UsbmuxdConnection, FfiError>
|
||||
tcp_new(const idevice_sockaddr* addr, idevice_socklen_t addr_len, uint32_t tag);
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
static std::optional<UsbmuxdConnection>
|
||||
unix_new(const std::string& path, uint32_t tag, FfiError& err);
|
||||
static Result<UsbmuxdConnection, FfiError> unix_new(const std::string& path, uint32_t tag);
|
||||
#endif
|
||||
static std::optional<UsbmuxdConnection> default_new(uint32_t tag, FfiError& err);
|
||||
static Result<UsbmuxdConnection, FfiError> default_new(uint32_t tag);
|
||||
|
||||
~UsbmuxdConnection() noexcept = default;
|
||||
UsbmuxdConnection(UsbmuxdConnection&&) noexcept = default;
|
||||
UsbmuxdConnection& operator=(UsbmuxdConnection&&) noexcept = default;
|
||||
UsbmuxdConnection(const UsbmuxdConnection&) = delete;
|
||||
UsbmuxdConnection& operator=(const UsbmuxdConnection&) = delete;
|
||||
~UsbmuxdConnection() noexcept = default;
|
||||
UsbmuxdConnection(UsbmuxdConnection&&) noexcept = default;
|
||||
UsbmuxdConnection& operator=(UsbmuxdConnection&&) noexcept = default;
|
||||
UsbmuxdConnection(const UsbmuxdConnection&) = delete;
|
||||
UsbmuxdConnection& operator=(const UsbmuxdConnection&) = delete;
|
||||
|
||||
std::optional<std::vector<UsbmuxdDevice>> get_devices(FfiError& err) const;
|
||||
std::optional<std::string> get_buid(FfiError& err) const;
|
||||
std::optional<PairingFile> get_pair_record(const std::string& udid, FfiError& err);
|
||||
Result<std::vector<UsbmuxdDevice>, FfiError> get_devices() const;
|
||||
Result<std::string, FfiError> get_buid() const;
|
||||
Result<PairingFile, FfiError> get_pair_record(const std::string& udid);
|
||||
|
||||
std::optional<Idevice>
|
||||
connect_to_device(uint32_t device_id, uint16_t port, const std::string& path, FfiError& err) &&;
|
||||
std::optional<Idevice>
|
||||
connect_to_device(uint32_t, uint16_t, const std::string&, FfiError&) & = delete;
|
||||
std::optional<Idevice>
|
||||
connect_to_device(uint32_t, uint16_t, const std::string&, FfiError&) const& = delete;
|
||||
Result<Idevice, FfiError>
|
||||
connect_to_device(uint32_t device_id, uint16_t port, const std::string& path) &&;
|
||||
Result<Idevice, FfiError> connect_to_device(uint32_t, uint16_t, const std::string&) & = delete;
|
||||
Result<Idevice, FfiError>
|
||||
connect_to_device(uint32_t, uint16_t, const std::string&) const& = delete;
|
||||
|
||||
UsbmuxdConnectionHandle* raw() const noexcept { return handle_.get(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user