Skip to content

Commit

Permalink
Merge branch 'release/0.8.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Arvtesh committed Mar 10, 2018
2 parents fe0a7a2 + 286a4ee commit 1ac4c39
Show file tree
Hide file tree
Showing 45 changed files with 64,474 additions and 1,029 deletions.
1 change: 1 addition & 0 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ branches:
skip_commits:
files:
- '**/*.md'
- '**/*.txt'

install:
- cmd: git submodule -q update --init
Expand Down
35 changes: 31 additions & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ root = true
# Use tabs for indentation.
[*]
indent_style = tab
trim_trailing_whitespace = true
insert_final_newline = true
# (Please don't specify an indent_size here; that has too many unintended consequences.)

# Code files
Expand All @@ -20,6 +22,11 @@ indent_size = 2
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2

# Yml config files
[*.{yml,yaml}]
indent_style = space
indent_size = 2

# JSON files
[*.json]
indent_size = 2
Expand All @@ -28,6 +35,7 @@ indent_size = 2
[*.{cs,vb}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true

# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
Expand All @@ -41,8 +49,8 @@ dotnet_style_predefined_type_for_member_access = true:warning
# Suggest more modern language features when available
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
dotnet_style_explicit_tuple_names = true:suggestion

# CSharp code style settings:
Expand All @@ -65,14 +73,33 @@ csharp_style_expression_bodied_accessors = true:none
# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_inlined_variable_declaration = true:warning
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion

csharp_prefer_simple_default_expression = true:suggestion
csharp_prefer_braces = true:warning

# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

# Formatting settings
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left

csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_parentheses = false

csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
39 changes: 38 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,41 @@ 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/).

-----------------------
## [Unreleased]

-----------------------
## [0.8.0] - 2018-03-10

### Added
- Added `IAsyncCompletionSource.Operation` property to match `TaskCompletionSource` interface.
- Added new constructor to `AsyncResult`.
- Added `AsyncResult.Start` method to match `Task` interface.
- Added `AsyncResult.OnStarted` virtual method.
- Added `WhenAll`/`WhenAny` static helpers for `AsyncResult`.
- Added `ConfigureAwait` extensions for `IAsyncOperation`.
- Added `Task` extension methods to that convert it to an `AsyncResult` instance.
- Added `AsyncResult.Retry` methods.
- Added `Wait` overloads to match `Task` interface.

### Removed
- Removed `AsyncResult.TryCreateAsyncWaitHandle` helper.

### Changed
- Modified `AsyncResultAwaiter` implementation to throw if the operation was canceled or faulted (to match `TaskAwaiter` behaviour).
- Implemented `AsyncCompletionSource` as a sealed analog of `TaskCompletionSource`.
- Removed public completion methods from `AsyncResult` (moved them to `AsyncCompletionSource`).
- Made `SpinUntilCompleted` an extension method (was `AsyncResult` instance method).
- Changed `IAsyncOperation.Exception` type to `AggregateException` to match `Task`.
- Changed `IAsyncOperationEvents.Completed` event signature & behaviour to always execute handler (event if it was registered after the comperation has copleted).
- Removed `AsyncResult` constructors that accepted exceptions.
- Changed `AsyncResult.Result` property to throw `AggregateException` when faulted or canceled to mathch `Task` behaviour.

### Fixed
- `AsyncResultQueue` now does not remove uncompleted operations from the queue.
- `AsyncResult.Exception` now only returns non-null value when the operation is faulted.

-----------------------
## [0.7.1] - 2018-02-14

### Added
Expand All @@ -11,8 +46,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/); this proj
- Added `IsEmpty` property to `AsyncResultQueue`.

### Changed
- `AsyncResult` implemenatino is changed to prevent returning null operation result when the operation is completed in some cases.
- `AsyncResult` implemenation is changed to prevent returning null operation result when the operation is completed in some cases.

-----------------------
## [0.7.0] - 2018-02-10

### Added
Expand All @@ -26,6 +62,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/); this proj
### Changed
- Renamed `AsyncOperationStatus` values to match [TastStatus](https://msdn.microsoft.com/ru-ru/library/system.threading.tasks.taskstatus(v=vs.110).aspx).

-----------------------
## [0.3.1] - 2017-08-01

### Added
Expand Down
160 changes: 152 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,174 @@

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)
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)](https://github.com/Arvtesh/UnityFx.Async/releases)
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) [![NuGet](https://img.shields.io/nuget/vpre/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.3.1-green.svg)](https://assetstore.unity.com/packages/tools/asynchronous-operations-for-unity-96696)

## Synopsis

Unity3d extensions for asynchronous operations. The library provides a set of classes and interfaces that can be used very much like [TPL](https://msdn.microsoft.com/ru-ru/library/dd460717(v=vs.110).aspx) tasks.
*UnityFx.Async* is a set of 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. At its core library defines a container ([AsyncResult](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResult.html)) for an asynchronous operation state and result value (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).

Please see [CHANGELOG](CHANGELOG.md) for information on recent changes.
Library is designed as a lightweight and portable [TPL](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl) alternative (not a replacement though) for [Unity3d](https://unity3d.com). Main design goals are:
- Minimum object size and allocations.
- Multithreading support. 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 most cases library classes can be used just 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> any operations in coroutines and net35-compilance.

The comparison table below shows how *UnityFx.Async* entities relate to [Tasks](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task):

TPL | UnityFx.Async | Notes
----|---------------|------
[Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) | [AsyncResult](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResult.html), [IAsyncOperation](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.IAsyncOperation.html) | Represents an asynchronous operation.
[Task&lt;TResult&gt;](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1) | [AsyncResult&lt;TResult&gt;](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResult-1.html), [IAsyncOperation&lt;TResult&gt;](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.IAsyncOperation-1.html) | Represents an asynchronous operation that can return a value.
[TaskStatus](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskstatus) | [AsyncOperationStatus](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncOperationStatus.html) | Represents the current stage in the lifecycle of an asynchronous operation.
[TaskCreationOptions](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions) | - | Specifies flags that control optional behavior for the creation and execution of asynchronous operations.
[TaskContinuationOptions](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcontinuationoptions) | TODO | Specifies the behavior for an asynchronous operation that is created by using continuation methods (`ContinueWith`).
[TaskCanceledException](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcanceledexception) | - | Represents an exception used to communicate an asynchronous operation cancellation.
[TaskCompletionSource&lt;TResult&gt;](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1) | [AsyncCompletionSource](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncCompletionSource.html), [IAsyncCompletionSource](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.IAsyncCompletionSource.html), [AsyncCompletionSource&lt;TResult&gt;](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncCompletionSource-1.html), [IAsyncCompletionSource&lt;TResult&gt;](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.IAsyncCompletionSource-1.html) | Represents the producer side of an asyncronous operation unbound to a delegate.
[TaskScheduler](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler) | - | Represents an object that handles the low-level work of queuing asynchronous operations onto threads.
[TaskFactory](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskfactory), [TaskFactory&lt;TResult&gt;](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskfactory-1) | - | Provides support for creating and scheduling asynchronous operations.
&#45; | [AsyncResultQueue&lt;T&gt;](https://arvtesh.github.io/UnityFx.Async/api/netstandard2.0/UnityFx.Async.AsyncResultQueue-1.html) | A FIFO queue of asynchronous operations executed sequentially.

Please note that the library is NOT a replacement for [TPL](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl). It is recommended to use [TPL](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl) in general and only switch to *UnityFx.Async* if one of the following applies:
- .NET 3.5/[Unity3d](https://unity3d.com) compatibility is required.
- Memory usage is a concern ([Tasks](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) tend to allocate quite much memory).
- An extendable [IAsyncResult](https://docs.microsoft.com/en-us/dotnet/api/system.iasyncresult) implementation is needed.

## Code Example
Typical use-case of the library is wrapping [Unity3d](https://unity3d.com) web requests in [Task-based Asynchronous Pattern](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-based-asynchronous-programming) manner:
```csharp
public IAsyncOperation<Texture2D> LoadTextureAsync(string textureUrl)
{
var result = new AsyncCompletionSource<Texture2D>();
StartCoroutine(LoadTextureInternal(result, textureUrl));
return result.Operation;
}

private IEnumerator LoadTextureInternal(IAsyncCompletionSource<Texture2D> op, string textureUrl)
{
var www = UnityWebRequestTexture.GetTexture(textureUrl);
yield return www.Send();

if (www.isNetworkError || www.isHttpError)
{
op.SetException(new Exception(www.error));
}
else
{
op.SetResult(((DownloadHandlerTexture)www.downloadHandler).texture);
}
}
```
Once that is done we can use `LoadTextureAsync()` result in many ways. For example we can yield it in Unity coroutine to wait for its completion:
```csharp
IEnumerator WaitForLoadOperationInCoroutine(string textureUrl)
{
var op = LoadTextureAsync(textureUrl);
yield return op;

if (op.IsCompletedSuccessfully)
{
Debug.Log("Yay!");
}
else if (op.IsFaulted)
{
Debug.LogException(op.Exception);
}
else if (op.IsCanceled)
{
Debug.LogWarning("The operation was canceled.");
}
}
```
With Unity 2017+ and .NET 4.6 scripting backed it can be used just like a [Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task). The await continuation is scheduled on the captured [SynchronizationContext](https://docs.microsoft.com/en-us/dotnet/api/system.threading.synchronizationcontext) (if any):
```csharp
async Task WaitForLoadOperationWithAwait(string textureUrl)
{
try
{
var texture = await LoadTextureAsync(textureUrl);
Debug.Log("Yay! The texture is loaded!");
}
catch (OperationCanceledException)
{
Debug.LogWarning("The operation was canceled.");
}
catch (Exception e)
{
Debug.LogException(e);
}
}
```
An operation can have any number of completion callbacks registered:
```csharp
void WaitForLoadOperationInCompletionCallback(string textureUrl)
{
LoadTextureAsync(textureUrl).AddCompletionCallback(op =>
{
if (op.IsCompletedSuccessfully)
{
var texture = (op as IAsyncOperation<Texture2D>).Result;
Debug.Log("Yay!");
}
else if (op.IsFaulted)
{
Debug.LogException(op.Exception);
}
else if (op.IsCanceled)
{
Debug.LogWarning("The operation was canceled.");
}
});
}
```
Also one can access/wait for operations from other threads:
```csharp
void WaitForLoadOperationInAnotherThread(string textureUrl)
{
var op = LoadTextureAsync(textureUrl);

ThreadPool.QueueUserWorkItem(
args =>
{
try
{
var texture = (args as IAsyncOperation<Texture2D>).Join();

// The texture is loaded
}
catch (OperationCanceledException)
{
// The operation was canceled
}
catch (Exception)
{
// Load failed
}
},
op);
}
```

## Motivation
The project was initially created to help author with his [Unity3d](https://unity3d.com) projects. Unity's [AsyncOperation](https://docs.unity3d.com/ScriptReference/AsyncOperation.html) and the like can only be used in coroutines, cannot be extended and mostly do not return result or error information, .NET 3.5 does not provide much help either and even with .NET 4.6 support compatibility requirements often do not allow using [Tasks](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task). When I caught myself writing the same asynchronous operation wrappers in each project I decided to share my experience for the best of human kind.

## Documentation
Please see the links below for extended information on the product:
- [Documentation](https://arvtesh.github.io/UnityFx.Async/articles/intro.html).
- [API Reference](https://arvtesh.github.io/UnityFx.Async/api/index.html).
- [CHANGELOG](CHANGELOG.md).

## Software requirements

## Useful links
- [Microsoft Visual Studio 2017](https://www.visualstudio.com/vs/community/)
- [Unity3d](https://store.unity.com/)
- [Unity Asset Store](https://assetstore.unity.com)

## Contributing

Please see [contributing guide](CONTRIBUTING.md) for details.

## License

Please see the [![license](https://img.shields.io/github/license/Arvtesh/UnityFx.Async.svg)](LICENSE.md) for details.
Please see the [![license](https://img.shields.io/github/license/Arvtesh/UnityFx.Async.svg)](LICENSE.md) for details.
2 changes: 1 addition & 1 deletion src/CodingConventions
Binary file added src/Dependencies/UnityEngine.dll
Binary file not shown.
Loading

0 comments on commit 1ac4c39

Please sign in to comment.