Skip to content

Commit

Permalink
Merge branch 'release/0.9.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
Arvtesh committed Jun 9, 2018
2 parents fbf50d1 + 0182948 commit 3bd906b
Show file tree
Hide file tree
Showing 55 changed files with 2,870 additions and 1,125 deletions.
27 changes: 24 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,40 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/).

-----------------------
## [0.9.3] - unreleased
## [0.9.3] - 2018.06.09

### Added
- Added push-based progress reporting support.
- Added `AsyncResult.Delay(float)` overloads.
- Added `AsyncCreationOptions.SuppressCancellation` option.
- Added update sources for `LateUpdate`, `FixedUpdate` and end-of-frame updates.
- Added `SynchronizationContext` for the main thread (if not set by Unity).
- Added methods `AsyncUtility.PostToMainThread`, `AsyncUtility.SendToMainThread` as `AsyncUtility.InvokeOnMainThread`.
- Added new `FromAction` overloads.

### Changed
- Significantly reduced number of memory allocations when adding continuations.
- Changed signature of the `IAsyncContinuation.Invoke` method.
- Changed `AsyncResult.OnCancel` implementation to do nothing (previously it threw `NotSupportedException`).

### Fixed
- Fixed exception when removing listeners while in `AsyncUpdateSource.OnError` / `AsyncUpdateSource.OnCompleted` / `AsyncUpdateSource.Dispose`.
- Fixed `AsyncResult.MoveNext` to always return `true` while the operation is not completed.
- Fixed `AsyncResult` construction code not working as intended when `AsyncCreationOptions` are specified.

### Removed
- Removed `AsyncOperationCallback` delegate type.

-----------------------
## [0.9.2] - 2018.05.25

### Added
- Added pull-based progress support (`IAsyncOperation.Progress`).
- Added pull-based progress reporting support.
- Added new methods to `IAsyncUpdateSource`.
- Added `AsyncUpdateSource` class as default `IAsyncUpdateSource` implementation.
- `IAsyncOperation<T>` now inherits `IObservable<T>`.

### Changed
- Renamed `(Try)AddCompletionCallback`/`RemoveCompletionCallback` methods to `(Try)AddContinuation`/`RemoveContinuation`.
- Changed `IAsyncOperation.Exception` type to `Exception`.
- Changed `IAsyncOperationEvents.Completed` type to `AsyncCompletedEventHandler`.

Expand Down
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ Channel | UnityFx.Async |
AppVeyor | [![Build status](https://ci.appveyor.com/api/projects/status/hfmq9vow53al7tpd/branch/master?svg=true)](https://ci.appveyor.com/project/Arvtesh/unityfx-async/branch/master) [![AppVeyor tests](https://img.shields.io/appveyor/tests/Arvtesh/unityFx-async.svg)](https://ci.appveyor.com/project/Arvtesh/unityfx-async/build/tests)
NuGet | [![NuGet](https://img.shields.io/nuget/v/UnityFx.Async.svg)](https://www.nuget.org/packages/UnityFx.Async)
Github | [![GitHub release](https://img.shields.io/github/release/Arvtesh/UnityFx.Async.svg?logo=github)](https://github.com/Arvtesh/UnityFx.Async/releases)
Unity Asset Store | [![Asynchronous operations for Unity](https://img.shields.io/badge/tools-v0.9.2-green.svg)](https://assetstore.unity.com/packages/tools/asynchronous-operations-for-unity-96696)
Unity Asset Store | [![Asynchronous operations for Unity](https://img.shields.io/badge/tools-v0.9.3-green.svg)](https://assetstore.unity.com/packages/tools/asynchronous-operations-for-unity-96696)

## Synopsis

*UnityFx.Async* is a set of classes and interfaces that extend [Unity3d](https://unity3d.com) asynchronous operations and can be used very much like [Task-based Asynchronous Pattern (TAP)](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-based-asynchronous-programming) in .NET or [Promises](https://developers.google.com/web/fundamentals/primers/promises) in Javascript. The library at its core defines a container ([AsyncResult](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResult.html)) for state and result value of an asynchronous operation (aka `promise` or `future`). In many aspects it mimics [Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) (for example, it can be used with `async`/`await` operators, supports continuations and synchronization context capturing).
*UnityFx.Async* introduces effective and portable asynchronous operations that can be used very much like [Tasks](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) in .NET or [Promises](https://developers.google.com/web/fundamentals/primers/promises) in JS. [AsyncResult](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResult.html) class is an implementation of a generic asynchronous operation (aka `promise` or `future`). In many aspects it mimics [Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) (for example, it can be used with `async`/`await` operators, supports continuations and synchronization context capturing) while maintaining Unity/net35 compatibility. It is a great foundation toolset for any Unity project.

Library is designed as a lightweight [Unity3d](https://unity3d.com)-compatible [Tasks](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) alternative (not a replacement though). Main design goals are:
- Minimum object size and number of allocations.
- Extensibility. The library operations are designed to be inherited.
- Extensibility. The library entities are designed to be easily extensible.
- Thread-safe. The library classes can be safely used from different threads (unless explicitly stated otherwise).
- [Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task)-like interface and behaviour. In many cases library classes can be used much like corresponding [TPL](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl) entities.
- [Unity3d](https://unity3d.com) compatibility. This includes possibility to <c>yield</c> operations in coroutines and net35-compilance.
- [Unity3d](https://unity3d.com)-specific features and compatibility. This includes possibility to <c>yield</c> operations in coroutines, `net35`-compilance, extensions of Unity asynchronous operations etc.

The table below summarizes differences berween *UnityFx.Async* and other popular asynchronous operation frameworks:

Expand All @@ -33,7 +33,7 @@ The table below summarizes differences berween *UnityFx.Async* and other popular
| Supports progress reporting | ✔️ | ✔️ | ✔️ |
| Supports child operations | - | - | ✔️ |
| Minimum operation data size for 32-bit systems (in bytes) | 28+ | 36+ | 40+ |
| Minimum number of allocations per continuation | 1+ | 5+ | 2+ |
| Minimum number of allocations per continuation | ~1 | 5+ | 2+ |

## Getting Started
### Prerequisites
Expand Down Expand Up @@ -166,9 +166,9 @@ Create an operation instance like this:
```csharp
var op = new AsyncCompletionSource<string>();
```
The type of the operation should reflect its result type. In this case we have created a special kind of operation - a completion source that incapsulated both producer and consumer interfaces (consumer side is represented via `IAsyncOperation` / `IAsyncOperation<TResult>` interfaces and producer side is `IAsyncCompletionSource` / `IAsyncCompletionSource<TResult>`, `AsyncCompletionSource` implements both of the interfaces).
The type of the operation should reflect its result type. In this case we create a special kind of operation - a completion source, that incapsulates both producer and consumer interfaces (consumer side is represented via `IAsyncOperation` / `IAsyncOperation<TResult>` interfaces and producer side is `IAsyncCompletionSource` / `IAsyncCompletionSource<TResult>`, `AsyncCompletionSource` implements both of the interfaces).

While operation is running its progress can be set as:
While operation is running its progress can be set like this:
```csharp
op.SetProgress(progressValue);
```
Expand Down Expand Up @@ -334,9 +334,21 @@ DownloadTextAsync("http://www.google.com")
If the [token](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken) passed to `WithCancellation()` is cancelled the target operation is cancelled as well (and that means cancelling all chained operations) as soon as possible. Cancellation might not be instant (depends on specific operation implementation). Also, please note that not all operations might support cancellation; in this case `Cancel()` will throw `NotSupportedException`.

### Progress reporting
Library operations support progress reporting via exposing `IAsyncOperation.Progress` property:
Library operations support progress reporting via exposing `IAsyncOperation.Progress` property and progress reporting events:
```csharp
var progress = op.Progess; // gets an operation progress as a float value in range [0, 1]
// subscribe to progress changed event
op.ProgressChanged += (sender, args) =>
{
Debug.Log("Progress = " + args.ProgressPercentage);
}

// add progress changed delegate
op.AddProgressCallback(op =>
{
Debug.Log("Progress = " + op.Progress);
});
```
There is `AsyncResult.GetProgress()` virtual method that is called when a progress values is requested. Finally there are producer-side methods like `AsyncCompletionSource.TrySetProgress()` that can set the progress value.

Expand All @@ -355,7 +367,7 @@ Completion callbacks are basicly low-level continuations. Just like continuation
```csharp
var op = DownloadTextAsync("http://www.google.com");
op.Completed += o => Debug.Log("1");
op.AddContinuation(o => Debug.Log("2"));
op.AddCompletionCallback(o => Debug.Log("2"));
```
That said, unlike `ContinueWith()`-like stuff completion callbacks cannot be chained and do not handle exceptions automatically. Throwing an exception from a completion callback results in unspecified behavior.

Expand All @@ -369,7 +381,7 @@ class MyContinuation : IAsyncContinuation
// ...
var op = DownloadTextAsync("http://www.google.com");
op.AddContinuation(new MyContinuation());
op.AddCompletionCallback(new MyContinuation());
```

### Disposing of operations
Expand Down
3 changes: 3 additions & 0 deletions src/Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,17 @@ function _PublishAssetStorePackage
{
param([string]$targetFramework)

$changelogPath = (Join-Path $scriptPath "..\CHANGELOG.md")
$filesToPublish = (Join-Path $scriptPath "UnityFx.Async.AssetStore\Assets\*")
$binToPublish =(Join-Path $binPath (Join-Path $targetFramework "\*"))
$publishPath = (Join-Path $assetStorePath (Join-Path $targetFramework "Assets"))
$publishPath2 = (Join-Path $publishPath "UnityFx.Async")
$publishBinPath = (Join-Path $publishPath "UnityFx.Async\Bin")

New-Item $publishBinPath -ItemType Directory
Copy-Item -Path $filesToPublish -Destination $publishPath -Force -Recurse
Copy-Item -Path $binToPublish -Destination $publishBinPath -Force -Recurse
Copy-Item -Path $changelogPath -Destination $publishPath2 -Force
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ LICENSE
https://github.com/Arvtesh/UnityFx.Async/blob/master/LICENSE.md

DOCUMENTATION
https://github.com/Arvtesh/UnityFx.Async
https://arvtesh.github.io/UnityFx.Async

SUPPORT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Alexander Bogarsukov.
// Licensed under the MIT license. See the LICENSE.md file in the project root for more information.

using System;
using UnityEngine;

namespace UnityFx.Async
{
/// <summary>
/// A wrapper for <see cref="AssetBundleRequest"/> with result value.
/// </summary>
/// <typeparam name="T">Result type.</typeparam>
public sealed class AssetBundleRequestResult<T> : AsyncResult<T> where T : UnityEngine.Object
{
#region data

private readonly AssetBundleRequest _op;

#endregion

#region interface

/// <summary>
/// Gets the underlying <see cref="AssetBundleRequest"/> instance.
/// </summary>
public AssetBundleRequest Request
{
get
{
return _op;
}
}

/// <summary>
/// Initializes a new instance of the <see cref="AssetBundleRequestResult{T}"/> class.
/// </summary>
/// <param name="op">Source web request.</param>
public AssetBundleRequestResult(AssetBundleRequest op)
: base(AsyncOperationStatus.Running)
{
_op = op;

if (op.isDone)
{
TrySetResult(op.asset as T, true);
}
else
{
#if UNITY_2017_2_OR_NEWER || UNITY_2018

// Starting with Unity 2017.2 there is AsyncOperation.completed event
op.completed += o => TrySetResult(o.asset as T);

#else

AsyncUtility.AddCompletionCallback(op, () => TrySetResult(_op.asset as T));

#endif
}
}

#endregion

#region AsyncResult

/// <inheritdoc/>
protected override float GetProgress()
{
return _op.progress;
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) Alexander Bogarsukov.
// Licensed under the MIT license. See the LICENSE.md file in the project root for more information.

using System;
using UnityEngine;

namespace UnityFx.Async
{
/// <summary>
/// A wrapper for <see cref="AsyncOperation"/> with result value.
/// </summary>
public class AsyncOperationResult : AsyncResult
{
#region data

private readonly AsyncOperation _op;

#endregion

#region interface

/// <summary>
/// Gets the underlying <see cref="AsyncOperation"/> instance.
/// </summary>
public AsyncOperation Operation
{
get
{
return _op;
}
}

/// <summary>
/// Initializes a new instance of the <see cref="AsyncOperationResult"/> class.
/// </summary>
/// <param name="op">Source web request.</param>
public AsyncOperationResult(AsyncOperation op)
: base(AsyncOperationStatus.Running)
{
_op = op;

if (op.isDone)
{
TrySetCompleted(true);
}
else
{
#if UNITY_2017_2_OR_NEWER || UNITY_2018

// Starting with Unity 2017.2 there is AsyncOperation.completed event
op.completed += o => TrySetCompleted();

#else

AsyncUtility.AddCompletionCallback(op, () => TrySetCompleted());

#endif
}
}

#endregion

#region AsyncResult

/// <inheritdoc/>
protected override float GetProgress()
{
return _op.progress;
}

#endregion
}
}
Loading

0 comments on commit 3bd906b

Please sign in to comment.