-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVirtualNode.cs
More file actions
157 lines (138 loc) · 6.66 KB
/
VirtualNode.cs
File metadata and controls
157 lines (138 loc) · 6.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Ramstack.FileSystem;
/// <summary>
/// Represents a node in a virtual file system, which could be either a file or a directory.
/// </summary>
public abstract class VirtualNode
{
private VirtualNodeProperties? _properties;
/// <summary>
/// Gets the <see cref="IVirtualFileSystem"/> instance associated with this node.
/// </summary>
public abstract IVirtualFileSystem FileSystem { get; }
/// <summary>
/// Gets a value indicating whether the file or directory is read-only.
/// </summary>
public bool IsReadOnly => FileSystem.IsReadOnly;
/// <summary>
/// Gets the full path of the file or directory.
/// </summary>
public string FullName { get; }
/// <summary>
/// Gets the name of the file or directory, excluding the path.
/// </summary>
public string Name => VirtualPath.GetFileName(FullName);
/// <summary>
/// Gets the file extension, including the leading dot <c>.</c>, or an empty string if there is no extension.
/// </summary>
public string Extension => VirtualPath.GetExtension(FullName);
/// <summary>
/// Initializes a new instance of the <see cref="VirtualNode"/> class.
/// </summary>
/// <param name="path">The full path of the file or directory.</param>
protected VirtualNode(string path)
{
Debug.Assert(VirtualPath.IsNormalized(path));
FullName = path;
}
/// <summary>
/// Initializes a new instance of the <see cref="VirtualNode"/> class with specified properties.
/// </summary>
/// <param name="path">The full path of the file or directory.</param>
/// <param name="properties">The properties of the file or directory.</param>
protected VirtualNode(string path, VirtualNodeProperties? properties) : this(path) =>
_properties = properties;
/// <summary>
/// Refreshes the state of the file or directory node, clearing any cached or stored values.
/// </summary>
public void Refresh()
{
_properties = null;
RefreshCore();
}
/// <summary>
/// Asynchronously determines whether the file or directory exists.
/// </summary>
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> representing the asynchronous operation.
/// The task result is <see langword="true"/> if the file or directory exists; otherwise, <see langword="false"/>.
/// </returns>
public ValueTask<bool> ExistsAsync(CancellationToken cancellationToken = default)
{
if (TryGetProperties(out var properties))
return new ValueTask<bool>(properties.Exists);
return ExistsCoreAsync(cancellationToken);
}
/// <summary>
/// Asynchronously retrieves the properties of the file or directory.
/// </summary>
/// <param name="refresh">A boolean indicating whether to refresh the state before retrieving the properties.</param>
/// <param name="cancellationToken">An optional cancellation token to cancel the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> representing the asynchronous operation,
/// with a result of type <see cref="VirtualNodeProperties"/> containing the file or directory properties.
/// </returns>
public ValueTask<VirtualNodeProperties> GetPropertiesAsync(bool refresh, CancellationToken cancellationToken = default)
{
var properties = _properties;
return refresh || properties is null
? GetPropertiesImpl(cancellationToken)
: new ValueTask<VirtualNodeProperties>(properties);
async ValueTask<VirtualNodeProperties> GetPropertiesImpl(CancellationToken token) =>
_properties = await GetPropertiesCoreAsync(token).ConfigureAwait(false) ?? VirtualNodeProperties.Unavailable;
}
/// <summary>
/// Core implementation for refreshing the state of the file or directory node,
/// clearing any cached or stored values.
/// </summary>
protected virtual void RefreshCore()
{
}
/// <summary>
/// Core implementation for asynchronously retrieving the current properties of the file or directory.
/// </summary>
/// <param name="cancellationToken">An optional cancellation token to cancel the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> representing the asynchronous operation,
/// with a result of type <see cref="VirtualNodeProperties"/> containing the updated properties,
/// or <see langword="null"/> if the properties cannot be retrieved.
/// </returns>
protected abstract ValueTask<VirtualNodeProperties?> GetPropertiesCoreAsync(CancellationToken cancellationToken);
/// <summary>
/// Core implementation for asynchronously determining whether the file or directory exists.
/// </summary>
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
/// <returns>
/// A <see cref="ValueTask{TResult}"/> representing the asynchronous operation.
/// The task result is <see langword="true"/> if the file or directory exists; otherwise, <see langword="false"/>.
/// </returns>
protected virtual async ValueTask<bool> ExistsCoreAsync(CancellationToken cancellationToken) =>
(await GetPropertiesAsync(refresh: true, cancellationToken).ConfigureAwait(false)).Exists;
/// <summary>
/// Attempts to retrieve the current properties of the file or directory.
/// </summary>
/// <param name="properties">When this method returns, contains the current <see cref="VirtualNodeProperties"/> if available;
/// otherwise, <see langword="null"/>.</param>
/// <returns>
/// <see langword="true"/> if the properties were successfully retrieved;
/// otherwise, <see langword="false"/> if the properties have not been set or have been invalidated.
/// </returns>
protected bool TryGetProperties([NotNullWhen(true)] out VirtualNodeProperties? properties)
{
properties = _properties;
return properties is not null;
}
/// <summary>
/// Ensures that the current file or directory is writable.
/// </summary>
/// <exception cref="NotSupportedException">Thrown when the current file or directory is read-only
/// and modifications are not supported.
/// </exception>
protected void EnsureWritable()
{
if (FileSystem.IsReadOnly)
throw new NotSupportedException("Write operations are not supported on a read-only instance.");
}
}