您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
158 行
5.0 KiB
158 行
5.0 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Unity.UIWidgets.async;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.UIWidgets.ui {
|
|
readonly struct _StoredMessage {
|
|
internal _StoredMessage(byte[] data, PlatformMessageResponseCallback callback) {
|
|
_data = data;
|
|
_callback = callback;
|
|
}
|
|
|
|
readonly byte[] _data;
|
|
public byte[] data => _data;
|
|
|
|
readonly PlatformMessageResponseCallback _callback;
|
|
public PlatformMessageResponseCallback callback => _callback;
|
|
}
|
|
|
|
class _RingBuffer<T> where T : struct {
|
|
readonly Queue<T> _queue;
|
|
|
|
internal _RingBuffer(int capacity) {
|
|
_capacity = capacity;
|
|
_queue = new Queue<T>(_capacity);
|
|
}
|
|
|
|
public int length => _queue.Count;
|
|
|
|
int _capacity;
|
|
public int capacity => _capacity;
|
|
|
|
public bool isEmpty => _queue.Count == 0;
|
|
|
|
Action<T> _dropItemCallback;
|
|
|
|
public Action<T> dropItemCallback {
|
|
set { _dropItemCallback = value; }
|
|
}
|
|
|
|
public bool push(in T val) {
|
|
if (_capacity <= 0)
|
|
return true;
|
|
|
|
int overflowCount = _dropOverflowItems(_capacity - 1);
|
|
_queue.Enqueue(val);
|
|
return overflowCount > 0;
|
|
}
|
|
|
|
public T? pop() {
|
|
return _queue.Count == 0 ? (T?) null : _queue.Dequeue();
|
|
}
|
|
|
|
int _dropOverflowItems(int lengthLimit) {
|
|
int result = 0;
|
|
while (_queue.Count > lengthLimit) {
|
|
T item = _queue.Dequeue();
|
|
_dropItemCallback?.Invoke(item);
|
|
|
|
result += 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public int resize(int newSize) {
|
|
_capacity = newSize;
|
|
return _dropOverflowItems(newSize);
|
|
}
|
|
}
|
|
|
|
public delegate Future DrainChannelCallback(byte[] data, PlatformMessageResponseCallback callback);
|
|
|
|
public class ChannelBuffers {
|
|
public const int kDefaultBufferSize = 1;
|
|
|
|
public const string kControlChannelName = "dev.uiwidgets/channel-buffers";
|
|
|
|
readonly Dictionary<string, _RingBuffer<_StoredMessage>> _messages =
|
|
new Dictionary<string, _RingBuffer<_StoredMessage>>();
|
|
|
|
_RingBuffer<_StoredMessage> _makeRingBuffer(int size) =>
|
|
new _RingBuffer<_StoredMessage>(size) {dropItemCallback = _onDropItem};
|
|
|
|
void _onDropItem(_StoredMessage message) {
|
|
message.callback(null);
|
|
}
|
|
|
|
public bool push(string channel, byte[] data, PlatformMessageResponseCallback callback) {
|
|
_RingBuffer<_StoredMessage> queue = _messages[channel];
|
|
if (queue == null) {
|
|
queue = _makeRingBuffer(kDefaultBufferSize);
|
|
_messages[channel] = queue;
|
|
}
|
|
|
|
bool didOverflow = queue.push(new _StoredMessage(data, callback));
|
|
if (didOverflow) {
|
|
Debug.LogWarning($"Overflow on channel: {channel}. " +
|
|
"Messages on this channel are being discarded in FIFO fashion. " +
|
|
"The engine may not be running or you need to adjust " +
|
|
"the buffer size of the channel.");
|
|
}
|
|
|
|
return didOverflow;
|
|
}
|
|
|
|
_StoredMessage? _pop(string channel) {
|
|
_RingBuffer<_StoredMessage> queue = _messages[channel];
|
|
_StoredMessage? result = queue?.pop();
|
|
return result;
|
|
}
|
|
|
|
void _resize(string channel, int newSize) {
|
|
_RingBuffer<_StoredMessage> queue = _messages[channel];
|
|
if (queue == null) {
|
|
queue = _makeRingBuffer(newSize);
|
|
_messages[channel] = queue;
|
|
}
|
|
else {
|
|
int numberOfDroppedMessages = queue.resize(newSize);
|
|
if (numberOfDroppedMessages > 0) {
|
|
Debug.LogWarning(
|
|
$"Dropping messages on channel \"{channel}\" as a result of shrinking the buffer size.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public Future drain(string channel, DrainChannelCallback callback) {
|
|
return Future.doWhile(() => {
|
|
_StoredMessage? message = _pop(channel);
|
|
if (!message.HasValue) {
|
|
return false;
|
|
}
|
|
|
|
return callback(message.Value.data, message.Value.callback);
|
|
});
|
|
}
|
|
|
|
string _getString(byte[] data) {
|
|
return Encoding.UTF8.GetString(data);
|
|
}
|
|
|
|
public void handleMessage(byte[] data) {
|
|
var command = _getString(data).Split('\r');
|
|
if (command.Length == /*arity=*/2 + 1 && command[0] == "resize") {
|
|
_resize(command[1], int.Parse(command[2]));
|
|
}
|
|
else {
|
|
throw new Exception($"Unrecognized command {command} sent to {kControlChannelName}.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static partial class ui_ {
|
|
public static readonly ChannelBuffers channelBuffers = new ChannelBuffers();
|
|
}
|
|
}
|