gen_readers

Generates the code for the IDataReader subtypes in the "BulkWriter" C# shared libraries.
git clone https://git.philomathiclife.com/repos/gen_readers
Log | Files | Refs | README

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 }