R-sharp/R#/ApiArgumentHelpers.vb

316 lines
12 KiB
VB.net

#Region "Microsoft.VisualBasic::97315af78fb2c2387e60300c863475df, R#\ApiArgumentHelpers.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.
' /********************************************************************************/
' Summaries:
' Code Statistics:
' Total Lines: 261
' Code Lines: 184 (70.50%)
' Comment Lines: 49 (18.77%)
' - Xml Docs: 91.84%
'
' Blank Lines: 28 (10.73%)
' File Size: 10.37 KB
' Module ApiArgumentHelpers
'
' Function: FileStreamWriter, GetDoubleRange, GetFileStream, GetNamedValueTuple, rangeFromVector
' slot
'
' /********************************************************************************/
#End Region
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
Imports Microsoft.VisualBasic.Language
Imports Microsoft.VisualBasic.Linq
Imports SMRUCC.Rsharp.Runtime
Imports SMRUCC.Rsharp.Runtime.Components
Imports SMRUCC.Rsharp.Runtime.Internal
Imports SMRUCC.Rsharp.Runtime.Internal.Object
Imports SMRUCC.Rsharp.Runtime.Internal.Object.Converts
Imports SMRUCC.Rsharp.Runtime.Interop
Imports SMRUCC.Rsharp.Runtime.Vectorization
Public Module ApiArgumentHelpers
''' <summary>
''' create a slot value reference inside a tuple <see cref="list"/> for construct a new list data
''' </summary>
''' <param name="name"></param>
''' <returns></returns>
Public Function slot(name As String) As ArgumentReference
Return CType(name, ArgumentReference)
End Function
''' <summary>
''' create a name tagged value object from a
''' given data source value
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="value">
''' any type of the .NET object
''' </param>
''' <param name="env"></param>
''' <param name="api">
''' the traceback tag
''' </param>
''' <returns></returns>
Public Function GetNamedValueTuple(Of T)(value As Object,
env As Environment,
<CallerMemberName>
Optional api$ = Nothing) As [Variant](Of NamedValue(Of T), Message)
If value Is Nothing Then
Return Nothing
End If
Select Case value.GetType
Case GetType(NamedValue(Of T))
Return DirectCast(value, NamedValue(Of T))
Case GetType(list)
Dim list As list = DirectCast(value, list)
Dim name As String = list.slots.Keys.First
value = DirectCast(value, list).slots(name)
value = RCType.CTypeDynamic(value, GetType(T), env)
Return New NamedValue(Of T) With {
.Name = name,
.Value = value,
.Description = list.getValue(Of String)("description", env)
}
Case Else
Return debug.stop({
"invalid data type for cast to a numeric range!",
"required: " & GetType(NamedValue(Of T)).FullName,
"given: " & value.GetType.FullName,
".NET traceback: " & api
}, env)
End Select
End Function
Public Function GetDoubleRange(value As Object, env As Environment,
Optional default$ = "0,1",
<CallerMemberName>
Optional api$ = Nothing) As [Variant](Of DoubleRange, Message)
If value Is Nothing Then
Return DoubleRange.TryParse([default])
End If
Select Case value.GetType
Case GetType(vector)
Return DirectCast(value, vector).rangeFromVector(env, api)
Case GetType(DoubleRange)
Return DirectCast(value, DoubleRange)
Case GetType(String)
Return DoubleRange.TryParse(DirectCast(value, String))
Case Else
If value.GetType.IsArray Then
Return New vector(DirectCast(value, Array), RType.GetRSharpType(GetType(Double))).rangeFromVector(env, api)
End If
Return debug.stop({
"invalid data type for cast to a numeric range!",
"required: " & GetType(DoubleRange).FullName,
"given: " & value.GetType.FullName
}, env)
End Select
End Function
<Extension>
Private Function rangeFromVector(v As vector, env As Environment, api$) As [Variant](Of DoubleRange, Message)
Dim vec As Double()
Select Case v.elementType.mode
Case TypeCodes.double
vec = CLRVector.asNumeric(v.data)
Case TypeCodes.integer
vec = CLRVector.asNumeric(v.data)
Case TypeCodes.string
If v.length = 1 Then
Return DoubleRange.TryParse(DirectCast(v.data.GetValue(Scan0), String))
Else
vec = v.data _
.AsObjectEnumerator(Of String) _
.Select(AddressOf Val) _
.ToArray
End If
Case Else
Return debug.stop({
"invalid vector data type!",
"mode: " & v.elementType.mode,
"raw: " & v.elementType.fullName
}, env)
End Select
If vec.Length < 2 Then
Return debug.stop({
"a numeric range required two boundary value at least!",
"api: " & api
}, env)
Else
Return New DoubleRange(vec)
End If
End Function
''' <summary>
''' open stream for file write
''' </summary>
''' <param name="file"></param>
''' <param name="write"></param>
'''
<Extension>
Public Function FileStreamWriter(env As Environment, file As Object, write As Action(Of Stream)) As Object
Dim stream As Stream
Dim is_file As Boolean = False
If file Is Nothing Then
stream = Console.OpenStandardOutput
ElseIf TypeOf file Is String Then
stream = DirectCast(file, String).Open(FileMode.OpenOrCreate, doClear:=True, [readOnly]:=False)
is_file = True
ElseIf TypeOf file Is Stream Then
stream = file
Else
Return Message.InCompatibleType(GetType(Stream), file.GetType, env)
End If
Call write(stream)
Call stream.Flush()
If is_file Then
Call stream.Close()
Call stream.Dispose()
End If
Return True
End Function
''' <summary>
''' the memory stream object that construct via the given byte array works in readonly mode!
''' </summary>
Const ReadOnlyRawByteStream As String = "the file open mode should be readonly when the input file data is a byte data collection."
''' <summary>
''' get a file stream object
''' </summary>
''' <param name="file">
''' the file resource could be one of the:
'''
''' 1. a valid file path to a filesystem location
''' 2. a stream object that can be read/write based on the <paramref name="mode"/> context
''' 3. a raw bytes array for construct a memory stream in this function(readonly)
''' </param>
''' <param name="mode"></param>
''' <param name="env"></param>
''' <param name="suppress"></param>
''' <returns></returns>
''' <remarks>
''' base on the value of <paramref name="mode"/>, this function has different behaviour:
'''
''' 1. <see cref="FileAccess.Read"/> for a readonly stream
''' 2. <see cref="FileAccess.ReadWrite"/> for create a stream could be used for write data
''' 3. <see cref="FileAccess.Write"/> will truncate the stream at first!
''' </remarks>
Public Function GetFileStream(file As Object,
mode As FileAccess,
env As Environment,
Optional suppress As Boolean = False,
<Out>
Optional ByRef is_filepath As Boolean = False) As [Variant](Of Stream, Message)
If TypeOf file Is vector Then
file = DirectCast(file, vector).data
End If
If TypeOf file Is Array AndAlso DirectCast(file, Array).Length = 1 Then
file = DirectCast(file, Array).GetValue(Scan0)
End If
If TypeOf file Is Array Then
file = TryCastGenericArray(DirectCast(file, Array), env)
If TypeOf file Is Message Then
Return DirectCast(file, Message)
End If
End If
If TypeOf file Is Array AndAlso DirectCast(file, Array).Length = 1 Then
file = DirectCast(file, Array).GetValue(Scan0)
End If
If file Is Nothing Then
Return Internal.debug.stop({"file output can not be nothing!"}, env, suppress)
Else
is_filepath = False
End If
If TypeOf file Is String Then
is_filepath = True
' from a local file
If mode = FileAccess.Read Then
Return DirectCast(file, String).Open(FileMode.Open, doClear:=False, [readOnly]:=True)
ElseIf mode = FileAccess.Write Then
Return DirectCast(file, String).Open(FileMode.OpenOrCreate, doClear:=True, [readOnly]:=False)
Else
Return DirectCast(file, String).Open(FileMode.OpenOrCreate, doClear:=False, [readOnly]:=False)
End If
ElseIf TypeOf file Is Stream OrElse TypeOf file Is MemoryStream Then
Return DirectCast(file, Stream)
ElseIf TypeOf file Is Byte() Then
If mode = FileAccess.Read Then
Return New MemoryStream(DirectCast(file, Byte()))
Else
Return Internal.debug.stop(ReadOnlyRawByteStream, env, suppress)
End If
ElseIf TypeOf file Is StreamWriter AndAlso mode = FileAccess.Write Then
Return DirectCast(file, StreamWriter).BaseStream
ElseIf file.GetType.IsArray Then
If mode = FileAccess.Read Then
Return New MemoryStream(CLRVector.asRawByte(file))
Else
Return Internal.debug.stop(ReadOnlyRawByteStream, env, suppress)
End If
Else
Return Message.InCompatibleType(GetType(Stream), file.GetType, env,, NameOf(file), suppress)
End If
End Function
End Module