Skip to content
Open
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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Uno.Core

Uno.Core is nventive's attempt at filling some gaps in the existing .net framework and related technologies; hence reducing friction
and increasing the predictability of the api. It consists of a set of helpers, extension methods and additional abstractions.

## Build status

| Target | Branch | Status | Usage |
| ------ | ------ | ------ | ----- |
| development | master |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/master?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/master) | For developing and testing |
| beta | beta |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/beta?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/beta) | Testing before release as stable |
| release | stable |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/stable?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/stable) | Last stable version |

## Package
[![NuGet](https://img.shields.io/nuget/v/Uno.Core.svg)](https://www.nuget.org/packages/Uno.Core/)

## Documentation
_Coming soon._
13 changes: 0 additions & 13 deletions Readme.md

This file was deleted.

30 changes: 21 additions & 9 deletions src/Uno.Core.Tests/Extensions/StringExtensionsFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,15 +315,27 @@ public void StringFormatsErrorHandlingAreIdentical()
[TestMethod]
public void CustomStringFormatsWithMultipleValues()
{
Assert.AreEqual(
StringExtensions.Format("For {0} and {1}?", 42, 3.1416),
"For 42 and 3.1416?");
Assert.AreEqual(
StringExtensions.Format("For {0:#.##;(#.##);ZERO} and {1:#.##;(#.##);ZERO}?", 42, 3.1416),
"For 42 and 3.14?");
Assert.AreEqual(
StringExtensions.Format("For {0:#.##;(#.##);ZERO;ONE}, {1:#.##;(#.##);ZERO;ONE} and {2:#.##;(#.##);ZERO;ONE}?", 42, 3.1416, 1.004),
"For 42, 3.14 and ONE?");
var previous = CultureInfo.CurrentUICulture;
try
{
CultureInfo.CurrentUICulture = new CultureInfo("en-US", false);

Assert.AreEqual(
StringExtensions.Format("For {0} and {1}?", 42, 3.1416),
"For 42 and 3.1416?");
Assert.AreEqual(
StringExtensions.Format("For {0:#.##;(#.##);ZERO} and {1:#.##;(#.##);ZERO}?", 42, 3.1416),
"For 42 and 3.14?");
Assert.AreEqual(
StringExtensions.Format(
"For {0:#.##;(#.##);ZERO;ONE}, {1:#.##;(#.##);ZERO;ONE} and {2:#.##;(#.##);ZERO;ONE}?", 42,
3.1416, 1.004),
"For 42, 3.14 and ONE?");
}
finally
{
CultureInfo.CurrentUICulture = previous;
}
}
}
}
115 changes: 115 additions & 0 deletions src/Uno.Core.Tests/Threading/LockAsyncFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// ******************************************************************
// Copyright � 2015-2018 nventive inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ******************************************************************
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.Threading;

namespace Uno.Core.Tests.Threading
{
[TestClass]
public class LockAsyncFixture

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AsyncLockFixture :)

{
[TestMethod]
public async Task BasicLock()
{
var gate = new AsyncLock();
var sync = new object();
var gate2 = new object();
var current = 0;
var maxCurrent = 0;
var waiting = 0;

var func1 = Funcs.Create(async ct => {

await Task.Yield();

lock (sync)
{
waiting++;
Monitor.Wait(sync);
}

using(await gate.LockAsync(ct))
{
lock (gate2)
{
current++;
maxCurrent = Math.Max(current, maxCurrent);
}

await Task.Delay(100);

lock (gate2)
{
current--;
}
}

return 42;
});

var c1 = func1(CancellationToken.None);
var c2 = func1(CancellationToken.None);

while (waiting != 2)
{
await Task.Delay(100);
}

lock(sync)
{
Monitor.PulseAll(sync);
}

await c1;
await c2;

Assert.AreEqual(1, maxCurrent);
}

[TestMethod]
public async Task CancelledLock()
{
var gate = new AsyncLock();

var func = Funcs.Create(async (int wait, CancellationToken ct) => {

using(await gate.LockAsync(ct))
{
await Task.Delay(wait, ct);
}

return 42;
});

using (await gate.LockAsync(CancellationToken.None))
{
var cts = new CancellationTokenSource();
var r1 = func(100000, cts.Token);

cts.Cancel();

Assert.AreEqual(TaskStatus.Canceled, r1.Status);
}

var r2 = await func(1000, CancellationToken.None);
Assert.AreEqual(42, r2);
}
}
}
34 changes: 17 additions & 17 deletions src/Uno.Core/Threading/AsyncLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@

namespace Uno.Threading
{
/// <summary>
/// An asynchronous lock, that can be used in conjuction with C# async/await
/// </summary>
public sealed class AsyncLock
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
/// <summary>
/// An asynchronous lock, that can be used in conjunction with C# async/await
/// </summary>
public sealed class AsyncLock
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

/// <summary>
/// Acquires the lock, then provides a disposable to release it.
/// </summary>
/// <param name="ct">A cancellation token to cancel the lock</param>
/// <returns>An IDisposable instance that allows the release of the lock.</returns>
public async Task<IDisposable> LockAsync(CancellationToken ct)
{
await _semaphore.WaitAsync(ct);
/// <summary>
/// Acquires the lock, then provides a disposable to release it.
/// </summary>
/// <param name="ct">A cancellation token to cancel the lock</param>
/// <returns>An IDisposable instance that allows the release of the lock.</returns>
public async Task<IDisposable> LockAsync(CancellationToken ct)
{
await _semaphore.WaitAsync(ct);

return Disposable.Create(() => _semaphore.Release());
}
}
return Disposable.Create(() => _semaphore.Release());
}
}
}
8 changes: 4 additions & 4 deletions src/Uno.Core/Threading/FastAsyncLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
namespace Uno.Threading
{
/// <summary>
/// An re-entrant asynchronous lock, that can be used in conjuction with C# async/await
/// An re-entrant asynchronous lock, that can be used in conjunction with C# async/await
/// </summary>
public sealed class FastAsyncLock
{
Expand Down Expand Up @@ -159,7 +159,7 @@ void Abort()

private void Dequeued()
{
// Dequeing may occures more than once. So move to next step only if item is really waiting!
// Dequeing may occured more than once. So move to next step only if item is really waiting!
switch (Interlocked.CompareExchange(ref _state, State.Entered, State.Waiting))
{
case State.Waiting:
Expand Down Expand Up @@ -201,7 +201,7 @@ public void Exit()
// As we are running asynchronous, it may occures that the inner task completes from another execution context (e.g. an event).
// So unlike the synchronous lock which must be exited from the same execution context / thread (otherwise we receive an SynchronizationLockException),
// here we cannot enforce the 'Exit' to be invoked only from the entering execution context (ie. check that '_owner._localMonitor.Value == this')
// Consequently, we have to handle concurrency with ReEntrency (Enter{Sync|Async} are not impacted since for those the caller did not received an 'Handle' yet)
// Consequently, we have to handle concurrency with Reentrency (Enter{Sync|Async} are not impacted since for those the caller did not received an 'Handle' yet)

if (Interlocked.Decrement(ref _count) == 0)
{
Expand All @@ -217,7 +217,7 @@ public void Exit()
}

/// <summary>
/// An handle on an async lock which makes sure that disposing it mutiple times won't exit the monitor multiple times
/// An handle on an async lock which makes sure that disposing it multiple times won't exit the monitor multiple times
/// </summary>
private class Handle : IDisposable
{
Expand Down