Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ objc2-model-io = { path = "framework-crates/objc2-model-io", version = "0.3.1",
objc2-multipeer-connectivity = { path = "framework-crates/objc2-multipeer-connectivity", version = "0.3.1", default-features = false }
objc2-natural-language = { path = "framework-crates/objc2-natural-language", version = "0.3.1", default-features = false }
objc2-nearby-interaction = { path = "framework-crates/objc2-nearby-interaction", version = "0.3.1", default-features = false }
objc2-network = { path = "framework-crates/objc2-network", version = "0.3.1", default-features = false }
objc2-network-extension = { path = "framework-crates/objc2-network-extension", version = "0.3.1", default-features = false }
objc2-notification-center = { path = "framework-crates/objc2-notification-center", version = "0.3.1", default-features = false }
objc2-osa-kit = { path = "framework-crates/objc2-osa-kit", version = "0.3.1", default-features = false }
Expand Down Expand Up @@ -415,6 +416,7 @@ objc2-model-io = { path = "framework-crates/objc2-model-io" }
objc2-multipeer-connectivity = { path = "framework-crates/objc2-multipeer-connectivity" }
objc2-natural-language = { path = "framework-crates/objc2-natural-language" }
objc2-nearby-interaction = { path = "framework-crates/objc2-nearby-interaction" }
objc2-network = { path = "framework-crates/objc2-network" }
objc2-network-extension = { path = "framework-crates/objc2-network-extension" }
objc2-notification-center = { path = "framework-crates/objc2-notification-center" }
objc2-osa-kit = { path = "framework-crates/objc2-osa-kit" }
Expand Down
1 change: 0 additions & 1 deletion crates/header-translator/configs/skipped.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ InterfaceBuilderKit = "TODO. Developer-only"
XcodeKit = "TODO. Developer-only"
StoreKitTest = "TODO. Developer-only"

Network = "TODO, see [#646](https://github.com/madsmtm/objc2/issues/646)"
DeviceDiscoveryUI = "Needs Network first"

BrowserKit = "TODO"
Expand Down
104 changes: 85 additions & 19 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
use std::fmt::Display;
use std::str::FromStr;
use std::sync::LazyLock;
use std::{fmt, iter, mem};
use std::{fmt, fmt::Display, iter, mem, str::FromStr, sync::LazyLock};

use clang::{CallingConvention, Entity, EntityKind, Nullability, Type, TypeKind};
use proc_macro2::{TokenStream, TokenTree};

use crate::context::Context;
use crate::display_helper::FormatterFn;
use crate::id::{ItemIdentifier, ItemTree};
use crate::name_translation::cf_no_ref;
use crate::protocol::ProtocolRef;
use crate::stmt::{anonymous_record_name, bridged_to, parse_class_generics, GenericWithBound};
use crate::stmt::{parse_superclasses, superclasses_required_items};
use crate::thread_safety::ThreadSafety;
use crate::unexposed_attr::UnexposedAttr;
use crate::{
context::Context,
display_helper::FormatterFn,
id::{ItemIdentifier, ItemTree},
name_translation::cf_no_ref,
protocol::ProtocolRef,
stmt::{
anonymous_record_name, bridged_to, parse_class_generics, parse_superclasses,
superclasses_required_items, GenericWithBound,
},
thread_safety::ThreadSafety,
unexposed_attr::UnexposedAttr,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
enum ParsePosition {
Expand Down Expand Up @@ -696,6 +697,9 @@ pub enum PointeeTy {
DispatchTypeDef {
id: ItemIdentifier,
},
NetworkTypeDef {
id: ItemIdentifier,
},
TypeDef {
id: ItemIdentifier,
to: Box<PointeeTy>,
Expand Down Expand Up @@ -808,7 +812,9 @@ impl PointeeTy {
.chain(result_type.required_items())
.chain(arguments.iter().flat_map(|arg| arg.required_items()))
.collect(),
Self::CFTypeDef { id, .. } | Self::DispatchTypeDef { id } => {
Self::CFTypeDef { id, .. }
| Self::DispatchTypeDef { id }
| Self::NetworkTypeDef { id } => {
vec![ItemTree::from_id(id.clone())]
}
Self::TypeDef { id, to } => {
Expand Down Expand Up @@ -865,7 +871,9 @@ impl PointeeTy {
.any(|arg| arg.requires_mainthreadmarker(self_requires))
|| result_type.requires_mainthreadmarker(self_requires)
}
Self::CFTypeDef { .. } | Self::DispatchTypeDef { .. } => false,
Self::CFTypeDef { .. } | Self::DispatchTypeDef { .. } | Self::NetworkTypeDef { .. } => {
false
}
Self::TypeDef { to, .. } => to.requires_mainthreadmarker(self_requires),
Self::CStr => false,
}
Expand Down Expand Up @@ -959,6 +967,7 @@ impl PointeeTy {
}
Self::CFTypeDef { id, .. } => write!(f, "{}", id.path()),
Self::DispatchTypeDef { id } => write!(f, "{}", id.path()),
Self::NetworkTypeDef { id } => write!(f, "{}", id.path()),
Self::TypeDef { id, .. } => write!(f, "{}", id.path()),
Self::CStr => write!(f, "CStr"),
})
Expand Down Expand Up @@ -1137,6 +1146,8 @@ impl PointeeTy {
// Dispatch objects have strong type-safety, and are thus
// safe in both positions.
Self::DispatchTypeDef { .. } => TypeSafety::SAFE,
// Akin to dispatch objects
Self::NetworkTypeDef { .. } => TypeSafety::SAFE,
// &CStr is safe as a parameter, though probably not when
// returning (since we wouldn't know the lifetime).
Self::CStr => TypeSafety::unsafe_in_return("must bound the lifetime"),
Expand Down Expand Up @@ -1219,9 +1230,10 @@ impl PointeeTy {

pub(crate) fn implementable(&self) -> Option<ItemTree> {
match self {
Self::CFTypeDef { id, .. } | Self::Class { id, .. } | Self::DispatchTypeDef { id } => {
Some(ItemTree::from_id(id.clone()))
}
Self::CFTypeDef { id, .. }
| Self::Class { id, .. }
| Self::DispatchTypeDef { id }
| Self::NetworkTypeDef { id } => Some(ItemTree::from_id(id.clone())),
// We shouldn't encounter this here, since `Self` is only on
// Objective-C methods, but if we do, it's very unclear how we
// should translate it.
Expand Down Expand Up @@ -1266,6 +1278,15 @@ impl PointeeTy {
_ => false,
}
}

fn is_network_type(&self) -> bool {
match self {
// Recurse into typedefs
Self::TypeDef { to, .. } => to.is_network_type(),
Self::NetworkTypeDef { .. } => true,
_ => false,
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -2039,6 +2060,21 @@ impl Ty {
};
}

// Handle other Network Objective-C objects.
name if name.starts_with("nw_")
&& inner.get_kind() == TypeKind::ObjCObjectPointer =>
{
let id = ItemIdentifier::new(&declaration, context);
let id = context.replace_typedef_name(id, false);
let pointee = Box::new(Self::Pointee(PointeeTy::NetworkTypeDef { id }));
return Self::Pointer {
nullability,
is_const,
lifetime,
pointee,
};
}

_ => {}
}

Expand Down Expand Up @@ -2565,6 +2601,15 @@ impl Ty {
}
}

/// Determine whether the pointee inside a `Pointer` is a Network object-like type.
fn is_network_type(&self) -> bool {
if let Self::Pointee(pointee_ty) = self.through_typedef() {
pointee_ty.is_network_type()
} else {
false
}
}

/// Determine whether the pointee inside a `Pointer` is the inner
/// struct/void type required for a type to be considered a CF type.
///
Expand Down Expand Up @@ -2920,6 +2965,9 @@ impl Ty {
Self::Pointer { pointee, .. } if pointee.is_dispatch_type() => {
items.push(ItemTree::dispatch("DispatchRetained"));
}
Self::Pointer { pointee, .. } if pointee.is_network_type() => {
items.push(ItemTree::dispatch("NWRetained"));
}
_ => {}
}
items.into_iter()
Expand Down Expand Up @@ -2960,6 +3008,14 @@ impl Ty {
(_, false) => ";\nret.map(|ret| unsafe { DispatchRetained::retain(ret) })",
}
};
let end_network = |nullability| {
match (nullability, returns_retained) {
(Nullability::NonNull, true) => ";\nlet ret = ret.expect(\"function was marked as returning non-null, but actually returned NULL\");\nunsafe { NWRetained::from_raw(ret) }",
(Nullability::NonNull, false) => ";\nlet ret = ret.expect(\"function was marked as returning non-null, but actually returned NULL\");\nunsafe { NWRetained::retain(ret) }",
(_, true) => ";\nret.map(|ret| unsafe { NWRetained::from_raw(ret) })",
(_, false) => ";\nret.map(|ret| unsafe { NWRetained::retain(ret) })",
}
};
let end_objc = |nullability| {
match (nullability, returns_retained) {
(Nullability::NonNull, true) => {
Expand Down Expand Up @@ -2989,7 +3045,10 @@ impl Ty {
// are a hint, and not an ABI stable promise.
if pointee.is_static_object() {
write!(f, "-> Option<&'static {}>", pointee.behind_pointer())
} else if pointee.is_cf_type() || pointee.is_dispatch_type() {
} else if pointee.is_cf_type()
|| pointee.is_dispatch_type()
|| pointee.is_network_type()
{
write!(f, "-> Option<NonNull<{}>>", pointee.behind_pointer())
} else if pointee.is_objc_type() {
write!(f, "-> *mut {}", pointee.behind_pointer())
Expand Down Expand Up @@ -3045,6 +3104,13 @@ impl Ty {
format!(" -> Option<DispatchRetained<{}>>", pointee.behind_pointer())
};
Some((res, start, end_dispatch(*nullability)))
} else if pointee.is_network_type() {
let res = if *nullability == Nullability::NonNull {
format!(" -> NWRetained<{}>", pointee.behind_pointer())
} else {
format!(" -> Option<NWRetained<{}>>", pointee.behind_pointer())
};
Some((res, start, end_network(*nullability)))
} else if pointee.is_objc_type() && !pointee.is_static_object() {
let res = if *nullability == Nullability::NonNull {
format!(" -> Retained<{}>", pointee.behind_pointer())
Expand Down
18 changes: 11 additions & 7 deletions crates/header-translator/src/unexposed_attr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use clang::source::{SourceLocation, SourceRange};
use clang::token::{Token, TokenKind};
use clang::{Entity, EntityKind};
use clang::{
source::{SourceLocation, SourceRange},
token::{Token, TokenKind},
Entity, EntityKind,
};
use proc_macro2::TokenStream;

use crate::context::{Context, MacroLocation};
Expand Down Expand Up @@ -41,7 +43,7 @@ impl UnexposedAttr {
get_arguments: impl FnOnce() -> TokenStream,
) -> Result<Option<Self>, ()> {
Ok(match s {
"CF_ENUM" | "JSC_CF_ENUM" | "DISPATCH_ENUM" | "NS_ENUM" => {
"CF_ENUM" | "JSC_CF_ENUM" | "DISPATCH_ENUM" | "NS_ENUM" | "NW_ENUM" => {
let _ = get_arguments();
Some(Self::Enum)
}
Expand Down Expand Up @@ -96,7 +98,8 @@ impl UnexposedAttr {
| "CM_RETURNS_RETAINED_BLOCK"
| "CM_RETURNS_RETAINED_PARAMETER"
| "CV_RETURNS_RETAINED"
| "CV_RETURNS_RETAINED_PARAMETER" => Some(Self::ReturnsRetained),
| "CV_RETURNS_RETAINED_PARAMETER"
| "NW_RETURNS_RETAINED" => Some(Self::ReturnsRetained),
"NS_RETURNS_NOT_RETAINED"
| "CF_RETURNS_NOT_RETAINED"
| "CM_RETURNS_NOT_RETAINED_PARAMETER" => Some(Self::ReturnsNotRetained),
Expand Down Expand Up @@ -139,8 +142,8 @@ impl UnexposedAttr {
let _ = get_arguments();
None
}
"CF_NOESCAPE" | "DISPATCH_NOESCAPE" | "NS_NOESCAPE" | "XCT_NOESCAPE"
| "XCUI_NOESCAPE" => Some(Self::NoEscape),
"CF_NOESCAPE" | "DISPATCH_NOESCAPE" | "NW_NOESCAPE" | "NS_NOESCAPE"
| "XCT_NOESCAPE" | "XCUI_NOESCAPE" => Some(Self::NoEscape),
"DISPATCH_NOTHROW" | "NS_SWIFT_NOTHROW" => Some(Self::NoThrow),
// TODO: We could potentially automatically elide this argument
// from the method call, though it's rare enough that it's
Expand Down Expand Up @@ -422,6 +425,7 @@ impl UnexposedAttr {
| "NS_REFINED_FOR_SWIFT"
| "AR_REFINED_FOR_SWIFT"
| "NS_SWIFT_DISABLE_ASYNC"
| "NW_SWIFT_DISABLE_ASYNC"
| "CP_STRUCT_REF" => None,
// Possibly interesting?
"DISPATCH_COLD" => None,
Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/topics/frameworks_list_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
| `MultipeerConnectivity` | [`objc2-multipeer-connectivity`](https://crates.io/crates/objc2-multipeer-connectivity) | [![docs.rs](https://docs.rs/objc2-multipeer-connectivity/badge.svg)](https://docs.rs/objc2-multipeer-connectivity/) |
| `NaturalLanguage` | [`objc2-natural-language`](https://crates.io/crates/objc2-natural-language) | [![docs.rs](https://docs.rs/objc2-natural-language/badge.svg)](https://docs.rs/objc2-natural-language/) |
| `NearbyInteraction` | [`objc2-nearby-interaction`](https://crates.io/crates/objc2-nearby-interaction) | [![docs.rs](https://docs.rs/objc2-nearby-interaction/badge.svg)](https://docs.rs/objc2-nearby-interaction/) |
| `Network` | [`objc2-network`](https://crates.io/crates/objc2-network) | [![docs.rs](https://docs.rs/objc2-network/badge.svg)](https://docs.rs/objc2-network/) |
| `NetworkExtension` | [`objc2-network-extension`](https://crates.io/crates/objc2-network-extension) | [![docs.rs](https://docs.rs/objc2-network-extension/badge.svg)](https://docs.rs/objc2-network-extension/) |
| `NotificationCenter` | [`objc2-notification-center`](https://crates.io/crates/objc2-notification-center) | [![docs.rs](https://docs.rs/objc2-notification-center/badge.svg)](https://docs.rs/objc2-notification-center/) |
| `OSAKit` | [`objc2-osa-kit`](https://crates.io/crates/objc2-osa-kit) | [![docs.rs](https://docs.rs/objc2-osa-kit/badge.svg)](https://docs.rs/objc2-osa-kit/) |
Expand Down
1 change: 0 additions & 1 deletion crates/objc2/src/topics/frameworks_list_unsupported.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
| `MobileCoreServices` | Deprecated, use CoreServices + UniformTypeIdentifiers instead. |
| `MusicKit` | Swift-only. |
| `NetFS` | Deprecated, use macFUSE or FSKit instead (probably). |
| `Network` | TODO, see [#646](https://github.com/madsmtm/objc2/issues/646). |
| `OpenAL` | Very C-centric, use newer Audio frameworks instead. |
| `OpenCL` | Very C-centric and old. |
| `PCSC` | Too low-level, consider crates like `pcsc` instead. |
Expand Down
3 changes: 3 additions & 0 deletions crates/test-frameworks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ test-frameworks = [
"objc2-multipeer-connectivity",
"objc2-natural-language",
"objc2-nearby-interaction",
"objc2-network",
"objc2-network-extension",
"objc2-notification-center",
"objc2-osa-kit",
Expand Down Expand Up @@ -381,6 +382,7 @@ objc2-fs-kit = ["dep:objc2-fs-kit"]
objc2-gl-kit = ["dep:objc2-gl-kit"]
objc2-open-gl = ["dep:objc2-open-gl"]
objc2-open-gl-es = ["dep:objc2-open-gl-es", "objc2-open-gl-es?/objc2-io-surface"]
objc2-network = ["dep:objc2-network"]

[dependencies]
block2 = { workspace = true, default-features = true }
Expand Down Expand Up @@ -418,6 +420,7 @@ objc2-intents = { workspace = true, optional = true, default-features = true }
objc2-map-kit = { workspace = true, optional = true, default-features = true }
objc2-media-player = { workspace = true, optional = true, default-features = true }
objc2-natural-language = { workspace = true, optional = true, default-features = true }
objc2-network = { workspace = true, optional = true, default-features = true }
objc2-network-extension = { workspace = true, optional = true, default-features = true }
objc2-os-log = { workspace = true, optional = true, default-features = true }
objc2-photos-ui = { workspace = true, optional = true, default-features = true }
Expand Down
Loading
Loading