Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gameplaykit] Add nullability to (generated and manual) bindings #14615

Merged
merged 15 commits into from
Apr 28, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 6 additions & 1 deletion src/GameplayKit/GKBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;

Expand All @@ -18,7 +20,10 @@ public GKGoal this [nuint index] {
}

public NSNumber this [GKGoal goal] {
get { return ObjectForKeyedSubscript (goal); }
// The docs show that ObjectForKeyedSubscript should return 0.0 if the GKGoal is not
// available but actually returns null: https://developer.apple.com/documentation/gameplaykit/gkbehavior/1388723-objectforkeyedsubscript?language=objc
// radar filed here: https://feedbackassistant.apple.com/feedback/9979863
get { return ObjectForKeyedSubscript (goal) ?? throw new ArgumentOutOfRangeException (nameof (goal)); }
set { SetObject (value, goal); }
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/GameplayKit/GKCompat.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Compatibility stubs

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand Down
4 changes: 3 additions & 1 deletion src/GameplayKit/GKComponentSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -19,7 +21,7 @@ public GKComponentSystem ()
{
}

public Type ComponentType {
public Type? ComponentType {
get { return Class.Lookup (ComponentClass); }
}

Expand Down
4 changes: 3 additions & 1 deletion src/GameplayKit/GKCompositeBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
// Copyright 2016 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;

namespace GameplayKit {
public partial class GKCompositeBehavior {

public GKBehavior this [nuint index] {
public new GKBehavior this [nuint index] {
get { return ObjectAtIndexedSubscript (index); }
}

Expand Down
4 changes: 3 additions & 1 deletion src/GameplayKit/GKEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -19,7 +21,7 @@ public void RemoveComponent (Type componentType)
RemoveComponent (GKState.GetClass (componentType, "componentType"));
}

public GKComponent GetComponent (Type componentType)
public GKComponent? GetComponent (Type componentType)
{
return GetComponent (GKState.GetClass (componentType, "componentType"));
}
Expand Down
2 changes: 2 additions & 0 deletions src/GameplayKit/GKGameModel.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#nullable enable

using System;

namespace GameplayKit {
Expand Down
6 changes: 4 additions & 2 deletions src/GameplayKit/GKGridGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2016 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using ObjCRuntime;
#if NET
Expand All @@ -19,12 +21,12 @@ namespace GameplayKit {
public partial class GKGridGraph {

#if !NET
public virtual GKGridGraphNode GetNodeAt (Vector2i position)
public virtual GKGridGraphNode? GetNodeAt (Vector2i position)
{
return GetNodeAt<GKGridGraphNode> (position);
}
#endif
public NodeType GetNodeAt<NodeType> (Vector2i position) where NodeType : GKGridGraphNode
public NodeType? GetNodeAt<NodeType> (Vector2i position) where NodeType : GKGridGraphNode
{
return Runtime.GetNSObject<NodeType> (_GetNodeAt (position));
}
Expand Down
6 changes: 4 additions & 2 deletions src/GameplayKit/GKObstacleGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2016 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand Down Expand Up @@ -54,12 +56,12 @@ public GKObstacleGraph (NSCoder coder) : base (coder)
{
}

public static GKObstacleGraph<NodeType> FromObstacles (GKPolygonObstacle [] obstacles, float bufferRadius)
public static new GKObstacleGraph<NodeType>? FromObstacles (GKPolygonObstacle [] obstacles, float bufferRadius)
{
return Runtime.GetNSObject <GKObstacleGraph<NodeType>> (GraphWithObstacles (obstacles, bufferRadius, new Class (typeof (NodeType))));
}

public NodeType [] GetNodes (GKPolygonObstacle obstacle)
public new NodeType [] GetNodes (GKPolygonObstacle obstacle)
{
return NSArray.ArrayFromHandle<NodeType> (_GetNodes (obstacle));
}
Expand Down
18 changes: 10 additions & 8 deletions src/GameplayKit/GKPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -25,8 +27,8 @@ public partial class GKPath {

public static GKPath FromPoints (Vector2[] points, float radius, bool cyclical)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

var buffer = IntPtr.Zero;
try {
Expand All @@ -42,8 +44,8 @@ public static GKPath FromPoints (Vector2[] points, float radius, bool cyclical)
[DesignatedInitializer]
public GKPath (Vector2 [] points, float radius, bool cyclical)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

var buffer = IntPtr.Zero;
try {
Expand All @@ -68,8 +70,8 @@ public GKPath (Vector2 [] points, float radius, bool cyclical)
#endif
public static GKPath FromPoints (Vector3 [] points, float radius, bool cyclical)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

var buffer = IntPtr.Zero;
try {
Expand All @@ -95,8 +97,8 @@ public static GKPath FromPoints (Vector3 [] points, float radius, bool cyclical)
#endif
public GKPath (Vector3 [] points, float radius, bool cyclical)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

var buffer = IntPtr.Zero;
try {
Expand Down
10 changes: 6 additions & 4 deletions src/GameplayKit/GKPolygonObstacle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -22,8 +24,8 @@ public partial class GKPolygonObstacle {

public static GKPolygonObstacle FromPoints (Vector2 [] points)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

var size = Marshal.SizeOf (typeof (Vector2));
var length = points.Length * size;
Expand All @@ -45,8 +47,8 @@ public static GKPolygonObstacle FromPoints (Vector2 [] points)

static unsafe IntPtr GetPointer (Vector2[] points)
{
if (points == null)
throw new ArgumentNullException ("points");
if (points is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points));

if (ctor_pointer != IntPtr.Zero) {
// This can occur of a previous call to the base ctor threw an exception
Expand Down
6 changes: 4 additions & 2 deletions src/GameplayKit/GKPrimitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2016 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using System.Runtime.InteropServices;
using ObjCRuntime;
Expand Down Expand Up @@ -72,8 +74,8 @@ public Vector3 [] Points {
return points ?? (points = new Vector3 [3]);
}
set {
if (value == null)
throw new ArgumentNullException (nameof (value));
if (value is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (value));
if (value.Length != 3)
throw new ArgumentOutOfRangeException (nameof (value), "The length of the Value array must be 3");
points = value;
Expand Down
12 changes: 7 additions & 5 deletions src/GameplayKit/GKState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -16,8 +18,8 @@ public partial class GKState {

internal static Class GetClass (Type type, string parameterName)
{
if (type == null)
throw new ArgumentNullException (parameterName);
if (type is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (parameterName));

var klass = new Class (type);
// most API do not accept null so we throw in managed code instead of crashing the app
Expand All @@ -29,11 +31,11 @@ internal static Class GetClass (Type type, string parameterName)

internal static Class GetClass (NSObject instance, string parameterName)
{
if (instance == null)
throw new ArgumentNullException (parameterName);
if (instance is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (parameterName));

var klass = instance.Class;
if ((klass == null) || (klass.Handle == IntPtr.Zero))
if ((klass is null) || (klass.Handle == IntPtr.Zero))
throw new ArgumentException ("Not an type exposed to ObjC", parameterName);

return klass;
Expand Down
6 changes: 4 additions & 2 deletions src/GameplayKit/GKStateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@
// Copyright 2015 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;

namespace GameplayKit {
public partial class GKStateMachine : NSObject {

public GKState GetState (Type stateType)
public GKState? GetState (Type stateType)
{
return GetState (GKState.GetClass (stateType, "stateType"));
}

public GKState GetState (GKState state)
public GKState? GetState (GKState state)
{
return GetState (GKState.GetClass (state, "state"));
}
Expand Down
6 changes: 4 additions & 2 deletions src/GameplayKit/NSArray_GameplayKit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// Copyright 2016 Xamarin Inc. All rights reserved.
//

#nullable enable

using System;
using Foundation;
using ObjCRuntime;
Expand All @@ -28,8 +30,8 @@ public static class NSArray_GameplayKit {
[Export ("shuffledArrayWithRandomSource:")]
public static T [] GetShuffledArray<T> (this NSArray This, GKRandomSource randomSource) where T : class, INativeObject
{
if (randomSource == null)
throw new ArgumentNullException (nameof (randomSource));
if (randomSource is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (randomSource));
return NSArray.ArrayFromHandle<T> (Messaging.IntPtr_objc_msgSend_IntPtr (This.Handle, Selector.GetHandle ("shuffledArrayWithRandomSource:"), randomSource.Handle));
}

Expand Down
42 changes: 42 additions & 0 deletions tests/monotouch-test/GameplayKit/GKBehaviorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Unit tests for GKBehavior
//
// Authors:
// TJ Lambert <TJ.Lambert@microsoft.com>
//
//
// Copyright 2022 Xamarin Inc. All rights reserved.
//

#if !__WATCHOS__

using System;
using NUnit.Framework;

using Foundation;
using GameplayKit;

namespace MonoTouchFixtures.GamePlayKit {
[TestFixture]
[Preserve (AllMembers = true)]
public class GKBehaviorTests {

[Test]
public void ObjectForKeyedSubscriptTest ()
{
// Create 2 GKGoals to use in the gkBehavior
var goal1 = GKGoal.GetGoalToReachTargetSpeed (10);
var goal2 = GKGoal.GetGoalToReachTargetSpeed (15);

// Create a GKGoal that will not be included in gkBehavior
var goal3 = GKGoal.GetGoalToReachTargetSpeed (15);

// Create a GKBehavior from those first 2 goals
var gkBehavior = GKBehavior.FromGoals (new GKGoal [] { goal1, goal2 });

// Searching the gkBehavior for a non-exisitant goal should throw an ArgumentOutOfRangeException
Assert.Throws<ArgumentOutOfRangeException> ( () => { _ = gkBehavior[goal3]; }, "The ObjectForKeyedSubscript indexer should throw ArgumentOutOfRangeException if the goal is not in the behavior's list of GKGoals.");
}
}
}
#endif