main.rs (14078B)
1 //! This crate generates the code for the `System.Data.IDataReader` 2 //! subtypes in the `BulkWriters128` and `BulkWriters256` C# libraries. 3 #![no_implicit_prelude] 4 #![deny( 5 unsafe_code, 6 unused, 7 warnings, 8 clippy::all, 9 clippy::cargo, 10 clippy::nursery, 11 clippy::pedantic 12 )] 13 #![allow( 14 clippy::arithmetic_side_effects, 15 clippy::implicit_return, 16 clippy::integer_arithmetic 17 )] 18 #[allow(unused_extern_crates)] 19 extern crate alloc; 20 #[allow(unused_extern_crates)] 21 extern crate core; 22 #[allow(unused_extern_crates)] 23 extern crate std; 24 use alloc::string::{String, ToString}; 25 use core::clone::Clone; 26 use core::convert::From; 27 use core::fmt::{self, Debug, Display, Formatter}; 28 use core::result::Result::{self, Ok}; 29 use std::env; 30 use std::fs::File; 31 use std::io::{Error, Write}; 32 fn main() -> Result<(), GenErr> { 33 #[allow(deprecated)] 34 let mut path0 = env::home_dir().ok_or(GenErr::HomeVarNotSet)?; 35 path0.push(".c#"); 36 let mut path1 = path0.clone(); 37 path0.push("BulkWriters128/IterDataReaders.cs"); 38 let mut f = File::options().write(true).create_new(true).open(path0)?; 39 path1.push("BulkWriters256/IterDataReaders.cs"); 40 let mut f2 = File::options().write(true).create_new(true).open(path1)?; 41 let mut s = String::with_capacity(270_988); 42 write(&mut f, 0, &mut s)?; 43 write(&mut f2, 128, &mut s)?; 44 Ok(()) 45 } 46 /// Writes the file. 47 /// `s` is used as a buffer to write an entire `IterDataReader` into 48 /// before being used by `f` to write to the underlying file descriptor. 49 /// `v` is the starting arity of tuples: 0 or 128. 50 fn write(f: &mut File, v: u8, s: &mut String) -> Result<(), Error> { 51 s.push_str("// This code was generated via a CLI app that used the source code in IterDataReaderBaseCase.cs as a template. 52 // To improve compilation performance, the code uses very little 'whitespace' beyond what is necessary and contains no documentation, warning suppressions, or comments. 53 using Serde.Bin.Ser; 54 using static SQLServer.Helpers; 55 using Std; 56 using Std.Iter; 57 using Std.Maybe; 58 using Std.Vec; 59 using System; 60 using System.Data; 61 using System.Data.SqlTypes; 62 #pragma warning disable CA1502, CA1505, CS8618 63 namespace SQLServer {\n"); 64 for i in (if v == 0 { 1 } else { v })..=(v + 127) { 65 s.push_str("sealed class IterDataReader<TRowIter,TRow,TProd,TErr,"); 66 for j in 0..=i { 67 Kind::T.write(s, j); 68 } 69 s.pop(); 70 s.push_str(">:IDataReader "); 71 for j in 0..=i { 72 Kind::Bound.write(s, j); 73 } 74 s.push_str( 75 "where TErr:notnull,IBulkRowError where TProd:notnull,IBinSerializable,IProduct<", 76 ); 77 for j in 0..=i { 78 Kind::T.write(s, j); 79 } 80 s.pop(); 81 s.push_str(r#">where TRow:notnull,ISum<TProd,TErr>where TRowIter:notnull,IFusedIterator<TRow>{internal IterDataReader(Maybe<ErrorTable>error,UserTable table,Prod<ulong,double>maxErrorsAllowed,ulong currentProcessed,ulong currentError,TRowIter iter,string processName,string userName,bool numericRoundAbort,string truncationStackTrace)=>(_error,_table,_errTableExists,_maxErrorsAllowed,CurrentProcessedCount,CurrentErrorCount,_iter,_errs,_isClosed,_numericRoundAbort,_current,_processName,_userName,_truncationStackTrace, _ser)=(error.IsSome?error.Unwrap():default,table,error.IsSome,maxErrorsAllowed,currentProcessed,currentError,iter,new Vec<Prod<nvarchar,nvarchar,varbinary>>(),false,numericRoundAbort,default!,processName,userName,new(truncationStackTrace),Serializer.New());readonly ErrorTable _error;readonly UserTable _table;TProd _current;Serializer _ser;readonly Prod<ulong,double>_maxErrorsAllowed;Vec<Prod<nvarchar,nvarchar,varbinary>>_errs;TRowIter _iter;readonly nvarchar _truncationStackTrace;readonly string _processName;readonly string _userName;internal ulong CurrentErrorCount;internal ulong CurrentProcessedCount;readonly bool _errTableExists;readonly bool _numericRoundAbort;bool _isClosed;public bool IsClosed=>_isClosed;double CurrentErrorRatio=>(double)CurrentErrorCount/CurrentProcessedCount;public int Depth=>0;public int FieldCount=>_table.ColumnCount;public object this[int ordinal]=>GetValue(ordinal);public object this[string columnName]=>GetValue(GetOrdinal(columnName));public int RecordsAffected=>-1;public void Close()=>Dispose();public void Dispose(){if(_isClosed){return;}(_isClosed,_current,_iter,_ser)=(true,default!,default!,default);if(_errTableExists){_=WriteErrors(in _error,ref _errs,_processName,_userName,ushort.MinValue);}_errs=new Vec<Prod<nvarchar,nvarchar,varbinary>>();}public sealed override bool Equals(object?_)=>false;public bool GetBoolean(int ordinal)=>(bool)GetValue(ordinal);public byte GetByte(int ordinal)=>(byte)GetValue(ordinal);public long GetBytes(int ordinal,long dataOffset,byte[]?buffer,int bufferOffset,int length){var val=GetValue(ordinal);var bytes=(byte[])val;var offset=(int)dataOffset;var len=bytes.Length-offset;if(len<=0){return 0L;}var count=Math.Min(len,length);var i=0;while(i<count){buffer![bufferOffset+i]=bytes[offset+i++];}return count;}public char GetChar(int ordinal){var val=(string)GetValue(ordinal);return val.Length==1?val[0]:throw new InvalidCastException();}public long GetChars(int ordinal,long dataOffset,char[]?buffer,int bufferOffset,int length){var val=GetValue(ordinal);var chars=(string)val;var offset=(int)dataOffset;var len=chars.Length-offset;if(len<=0){return 0L;}var count=Math.Min(len,length);var i=0;while(i<count){buffer![bufferOffset+i]=chars[offset+i++];}return count;}public IDataReader GetData(int _)=>throw new NotSupportedException();public string GetDataTypeName(int ordinal)=>GetFieldType(ordinal).Name;public DateTime GetDateTime(int ordinal){var type=GetFieldType(ordinal);return type==typeof(DateTime)?(DateTime)GetValue(ordinal):((SqlDateTime)GetValue(ordinal)).Value;}public decimal GetDecimal(int ordinal){var type=GetFieldType(ordinal);return type==typeof(SqlDecimal)?((SqlDecimal)GetValue(ordinal)).Value:((SqlMoney)GetValue(ordinal)).Value;}public double GetDouble(int ordinal)=>(double)GetValue(ordinal);public Type GetFieldType(int ordinal)=>_typeMap[_table[(ushort)ordinal].DataType];public float GetFloat(int ordinal)=>(float)GetValue(ordinal);public Guid GetGuid(int ordinal)=>(Guid)GetValue(ordinal);public sealed override int GetHashCode()=>0;public short GetInt16(int ordinal)=>(short)GetValue(ordinal);public int GetInt32(int ordinal)=>(int)GetValue(ordinal);public long GetInt64(int ordinal)=>(long)GetValue(ordinal);public string GetName(int ordinal)=>_table[(ushort)ordinal].Name;public int GetOrdinal(string name){for(ushort i=0;i<_table.ColumnCount;i++){if(_table.Schema.Name.Culture.CompareInfo.Compare(name,_table[i].Name,_table.Schema.Name.Options)==0){return i;}}throw new ArgumentException($"The column name, {name}, does not exist in {_table.IntoString()}.");}public DataTable GetSchemaTable(){DataTable schema=new(){MinimumCapacity=_table.ColumnCount,TableName=$"{_table.Schema.Name.Value}.{_table.Name}",Locale=_table.Schema.Name.Culture};_=schema.Columns.Add("Ordinal",typeof(ushort));_=schema.Columns.Add("ColumnName",typeof(string));_=schema.Columns.Add("DataType",typeof(Type));for(ushort i=0;i<_table.ColumnCount;i++){ref readonly var col=ref _table[i];_=schema.Rows.Add(i,col.Name,GetFieldType(i));}return schema;}public string GetString(int ordinal)=>(string)GetValue(ordinal);public object GetValue(int ordinal)=>ordinal switch{"#); 82 for j in 0..=i { 83 Kind::GetVal.write(s, j); 84 } 85 s.push_str("_=>throw new ArgumentOutOfRangeException(nameof(ordinal)),};public int GetValues(object[]values){var count=Math.Min(values.Length,_table.ColumnCount);for(var i=0;i<count;i++){values[i]=GetValue(i);}return count;}public bool IsDBNull(int ordinal)=>ordinal switch{"); 86 for j in 0..=i { 87 Kind::IsNull.write(s, j); 88 } 89 s.push_str(r#"_=>throw new ArgumentOutOfRangeException(nameof(ordinal)),};public bool NextResult(){if(_errTableExists){_=WriteErrors(in _error,ref _errs,_processName,_userName,ushort.MinValue);}(_errs,_current,_iter,_ser)=(new Vec<Prod<nvarchar,nvarchar,varbinary>>(),default!,default!,default);return false;}public bool Read(){while(true){if(CurrentErrorCount>_maxErrorsAllowed.Item0&&CurrentErrorRatio>_maxErrorsAllowed.Item1){if(_errTableExists){_=WriteErrors(in _error,ref _errs,_processName,_userName,ushort.MinValue);}(_errs,_current,_iter,_ser)=(new Vec<Prod<nvarchar,nvarchar,varbinary>>(),default!,default!,default);return false;}var cur=_iter!.Next();if(cur.IsNone){if(_errTableExists){_=WriteErrors(in _error,ref _errs,_processName,_userName,ushort.MinValue);}(_errs,_current,_iter,_ser)=(new Vec<Prod<nvarchar,nvarchar,varbinary>>(),default!,default!,default);return false;}CurrentProcessedCount++;var res=cur.Unwrap();if(res.Variant==Var2.V1){CurrentErrorCount++;if(_errTableExists){var err=res.Variant1;_=_errs.Push(new(err.Trace,err.Message,err.Data));_=WriteErrors(in _error,ref _errs,_processName,_userName,4095);}continue;}_current=res.Variant0;if(_errTableExists?TruncateOverflowCheckAndLog():TruncateOverflowCheck()){continue;}else{return true;}}}public sealed override string ToString()=>string.Empty;bool TruncateOverflowCheck(){"#); 90 for j in 0..=i { 91 Kind::Truncation.write(s, j); 92 } 93 s.push_str("return false;}bool TruncateOverflowCheckAndLog(){"); 94 for j in 0..=i { 95 Kind::TruncationLog.write(s, j); 96 } 97 s.push_str("return false;}}\n"); 98 f.write_all(s.as_bytes())?; 99 s.clear(); 100 } 101 f.write_all(&[b'}'])?; 102 f.flush() 103 } 104 /// The source code for an `IterDataReader` has multiple areas dependent 105 /// on the n-arity tuple that is written to the table. The code of which 106 /// is different, so we model those differences here. 107 enum Kind { 108 /// Represents the sequence of type parameters T0...Tn. 109 T, 110 /// Represents the type bounds for T0...Tn. 111 Bound, 112 /// Represents the portion of the source code based on T0...Tn 113 /// in the `GetValue` function. 114 GetVal, 115 /// Represents the portion of the source code based on T0...Tn 116 /// in the `IsDBNull` function. 117 IsNull, 118 /// Represents the portion of the source code based on T0...Tn 119 /// in the `TruncateOverflowCheck` function. 120 Truncation, 121 /// Represents the portion of the source code based on T0...Tn 122 /// in the `TruncateOverflowCheckAndLog` function. 123 TruncationLog, 124 } 125 impl Kind { 126 /// Writes the source code related to a single type parameter. 127 fn write(self, buffer: &mut String, i: u8) { 128 let s = &i.to_string(); 129 match self { 130 Self::T => { 131 buffer.push('T'); 132 buffer.push_str(s); 133 buffer.push(','); 134 } 135 Self::Bound => { 136 buffer.push_str("where "); 137 buffer.push('T'); 138 buffer.push_str(s); 139 buffer.push_str(":struct,IDataType "); 140 } 141 Self::GetVal => { 142 buffer.push_str(s); 143 buffer.push_str("=>_current.Field"); 144 buffer.push_str(s); 145 buffer.push_str(".Val,"); 146 } 147 Self::IsNull => { 148 buffer.push_str(s); 149 buffer.push_str("=>_current.Field"); 150 buffer.push_str(s); 151 buffer.push_str(".IsNULL,"); 152 } 153 Self::Truncation => { 154 buffer.push_str("if(_current.Field"); 155 buffer.push_str(s); 156 buffer.push_str(".IsNULL){if(!_table["); 157 buffer.push_str(s); 158 buffer.push_str( 159 "].IsNullable){CurrentErrorCount++;return true;}}else if(_current.Field", 160 ); 161 buffer.push_str(s); 162 buffer.push_str(".TruncationWillOccur(_table["); 163 buffer.push_str(s); 164 buffer.push_str("],_numericRoundAbort)){CurrentErrorCount++;return true;}"); 165 } 166 Self::TruncationLog => { 167 buffer.push_str("if(_current.Field"); 168 buffer.push_str(s); 169 buffer.push_str(".IsNULL){if(!_table["); 170 buffer.push_str(s); 171 buffer.push_str( 172 r#"].IsNullable){CurrentErrorCount++;_=_current.Ser(ref _ser);_=_errs.Push(new(_truncationStackTrace,new($"NULLs are not allowed in {_table.IntoString()}.{_table["# 173 ); 174 buffer.push_str(s); 175 buffer.push_str(r#"].Name}."),varbinary.New(_ser.SerializedData)));_=WriteErrors(in _error,ref _errs,_processName,_userName,4095);_=_ser.Reset();return true;}}else if(_current.Field"#); 176 buffer.push_str(s); 177 buffer.push_str(".TruncationWillOccur(_table["); 178 buffer.push_str(s); 179 buffer.push_str(r#"],_numericRoundAbort)){CurrentErrorCount++;_=_current.Ser(ref _ser);_=_errs.Push(new(_truncationStackTrace,new($"{_current.Field"#); 180 buffer.push_str(s); 181 buffer.push_str( 182 ".Into()} would truncate or overflow in {_table.IntoString()}.{_table[", 183 ); 184 buffer.push_str(s); 185 buffer.push_str(r#"].Name}."),varbinary.New(_ser.SerializedData)));_=WriteErrors(in _error,ref _errs,_processName,_userName,4095);_=_ser.Reset();return true;}"#); 186 } 187 } 188 } 189 } 190 /// The errors possible. 191 enum GenErr { 192 /// Error when `$HOME` is not set. 193 HomeVarNotSet, 194 /// Error containing a general IO error. 195 Error(Error), 196 } 197 impl Display for GenErr { 198 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 199 match *self { 200 Self::HomeVarNotSet => f.write_str("$HOME is not set."), 201 Self::Error(ref e) => <Error as Display>::fmt(e, f), 202 } 203 } 204 } 205 impl Debug for GenErr { 206 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 207 <Self as Display>::fmt(self, f) 208 } 209 } 210 impl From<Error> for GenErr { 211 fn from(value: Error) -> Self { 212 Self::Error(value) 213 } 214 }