mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 00:02:54 +08:00
Remove Live<> wrapper until it is needed
This commit is contained in:
parent
8442b34e84
commit
9bf9a8c351
@ -1,104 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using Realms;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
namespace osu.Game.Database
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides a method of passing realm live objects across threads in a safe fashion.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// To consume this as a live instance, the live object should be stored and accessed via <see cref="Get"/> each time.
|
|
||||||
/// To consume this as a detached instance, assign to a variable of type <typeparam ref="T"/>. The implicit conversion will handle detaching an instance.
|
|
||||||
/// </remarks>
|
|
||||||
/// <typeparam name="T">The underlying object type. Should be a <see cref="RealmObject"/> with a primary key provided via <see cref="IHasGuidPrimaryKey"/>.</typeparam>
|
|
||||||
public class Live<T> : IEquatable<Live<T>>, IHasGuidPrimaryKey
|
|
||||||
where T : RealmObject, IHasGuidPrimaryKey
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The primary key of the object.
|
|
||||||
/// </summary>
|
|
||||||
public Guid Guid { get; }
|
|
||||||
|
|
||||||
public string ID
|
|
||||||
{
|
|
||||||
get => Guid.ToString();
|
|
||||||
set => throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ThreadLocal<T> threadValues;
|
|
||||||
|
|
||||||
private readonly T original;
|
|
||||||
|
|
||||||
private readonly IRealmFactory contextFactory;
|
|
||||||
|
|
||||||
public Live(T item, IRealmFactory contextFactory)
|
|
||||||
{
|
|
||||||
this.contextFactory = contextFactory;
|
|
||||||
|
|
||||||
original = item;
|
|
||||||
Guid = item.Guid;
|
|
||||||
|
|
||||||
threadValues = new ThreadLocal<T>(getThreadLocalValue);
|
|
||||||
|
|
||||||
// the instance passed in may not be in a managed state.
|
|
||||||
// for now let's immediately retrieve a managed object on the current thread.
|
|
||||||
// in the future we may want to delay this until the first access (only populating the Guid at construction time).
|
|
||||||
if (!item.IsManaged)
|
|
||||||
original = Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private T getThreadLocalValue()
|
|
||||||
{
|
|
||||||
var context = contextFactory.Context;
|
|
||||||
|
|
||||||
// only use the original if no context is available or the source realm is the same.
|
|
||||||
if (context == null || original.Realm?.IsSameInstance(context) == true) return original;
|
|
||||||
|
|
||||||
return context.Find<T>(ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve a live reference to the data.
|
|
||||||
/// </summary>
|
|
||||||
public T Get() => threadValues.Value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve a detached copy of the data.
|
|
||||||
/// </summary>
|
|
||||||
public T Detach() => Get().Detach();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wrap a property of this instance as its own live access object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lookup">The child to return.</param>
|
|
||||||
/// <typeparam name="TChild">The underlying child object type. Should be a <see cref="RealmObject"/> with a primary key provided via <see cref="IHasGuidPrimaryKey"/>.</typeparam>
|
|
||||||
/// <returns>A wrapped instance of the child.</returns>
|
|
||||||
public Live<TChild> WrapChild<TChild>(Func<T, TChild> lookup)
|
|
||||||
where TChild : RealmObject, IHasGuidPrimaryKey => new Live<TChild>(lookup(Get()), contextFactory);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Perform a write operation on this live object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="perform">The action to perform.</param>
|
|
||||||
public void PerformUpdate(Action<T> perform)
|
|
||||||
{
|
|
||||||
using (contextFactory.GetForWrite())
|
|
||||||
perform(Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator T?(Live<T>? wrapper)
|
|
||||||
=> wrapper?.Detach() ?? null;
|
|
||||||
|
|
||||||
public static implicit operator Live<T>(T obj) => obj.WrapAsUnmanaged();
|
|
||||||
|
|
||||||
public bool Equals(Live<T>? other) => other != null && other.Guid == Guid;
|
|
||||||
|
|
||||||
public override string ToString() => Get().ToString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -69,31 +68,5 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
return mapper.Map<T>(item);
|
return mapper.Map<T>(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wrap a managed instance of a realm object in a <see cref="Live{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item to wrap.</param>
|
|
||||||
/// <param name="contextFactory">A factory to retrieve realm contexts from.</param>
|
|
||||||
/// <typeparam name="T">The type of object.</typeparam>
|
|
||||||
/// <returns>A wrapped instance of the provided item.</returns>
|
|
||||||
public static Live<T> Wrap<T>(this T item, IRealmFactory contextFactory)
|
|
||||||
where T : RealmObject, IHasGuidPrimaryKey => new Live<T>(item, contextFactory);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wrap an unmanaged instance of a realm object in a <see cref="Live{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item to wrap.</param>
|
|
||||||
/// <typeparam name="T">The type of object.</typeparam>
|
|
||||||
/// <returns>A wrapped instance of the provided item.</returns>
|
|
||||||
/// <exception cref="ArgumentException">Throws if the provided item is managed.</exception>
|
|
||||||
public static Live<T> WrapAsUnmanaged<T>(this T item)
|
|
||||||
where T : RealmObject, IHasGuidPrimaryKey
|
|
||||||
{
|
|
||||||
if (item.IsManaged)
|
|
||||||
throw new ArgumentException("Provided item must not be managed", nameof(item));
|
|
||||||
|
|
||||||
return new Live<T>(item, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user