TinyCLR OS 3.0 Survey

Just to share that these have already been added::

internal sealed class RefBox<T> where T : class
    {
        public T Payload;

        public RefBox(T value)
        {
            Payload = value;
        }

        public T GetPayload()
        {
            return Payload;
        }
    }

    /// <summary>Closed constructed generic on a reference type (GENERICINST in metadata).</summary>
    internal sealed class GenericHolder
    {
        public RefBox<string> BoxField;

        public GenericHolder(string s)
        {
            BoxField = new RefBox<string>(s);
        }
    }

    /// <summary>Two-arity generic (Pair`2). Exercises declaring token on GENERICINST with two args.</summary>
    internal struct Pair<TU, TV>
    {
        public TU U;
        public TV V;

        public Pair(TU u, TV v)
        {
            U = u;
            V = v;
        }

        /// <summary>Instance method on constructed Pair; exercises MethodRef parent = TypeSpec.</summary>
        public string Describe()
        {
            return U.ToString() + "/" + V.ToString();
        }
    }

    /// <summary>Value-type constraint + instance methods on closed generic (MethodRef + FieldRef paths).</summary>
    internal sealed class ValCell<T> where T : struct
    {
        public T Cell;

        public void Write(T value)
        {
            Cell = value;
        }

        public T Read()
        {
            return Cell;
        }
    }

    internal static class Program {
        private static GenericHolder s_holder;
        static void Main() {
            var cnt = 0;
            var gpioController = GpioController.GetDefault();

            var led = gpioController.OpenPin(SC20260.GpioPin.PA8);
            led.SetDriveMode(GpioPinDriveMode.Output);
            var button = gpioController.OpenPin(SC20260.GpioPin.PB7);
            button.SetDriveMode(GpioPinDriveMode.InputPullUp);

            s_holder = new GenericHolder("generics-field-ok");
            Debug.WriteLine(s_holder.BoxField.GetPayload());

            // Local closed generic + array of constructed type
            var localBox = new RefBox<string>("generics-local-ok");
            Debug.WriteLine(localBox.GetPayload());

            var arr = new RefBox<string>[2];
            arr[0] = localBox;
            arr[1] = s_holder.BoxField;
            Debug.WriteLine(arr[0].Payload + " | " + arr[1].Payload);

            // Generic method (explicit type args); exercises generic method prefix in signatures
            var n = Identity<int>(7);
            Debug.WriteLine("Identity<int>: " + n.ToString());

            var s = Identity<string>("method-generic-ok");
            Debug.WriteLine(s);

            // Pair<int,int>: arity-2 GENERICINST; Describe() -> MethodRef on constructed type
            var pair = new Pair<int, int>(40, 2);
            Debug.WriteLine("Pair<int,int>: " + pair.Describe());

            // ValCell<int>: struct type arg + Write/Read -> MethodRef on ValCell`1<int>
            var cell = new ValCell<int>();
            cell.Write(12345);
            Debug.WriteLine("ValCell<int>.Read: " + cell.Read().ToString());

            while (true) {
                Debug.WriteLine("Hello from TinyCLR7.9! Count: " + cnt++);
                Thread.Sleep(250);
                led.Write(led.Read() == GpioPinValue.Low ? GpioPinValue.High : GpioPinValue.Low);

                if (button.Read() == GpioPinValue.Low)
                {
                    DoTest();                    
                }                
            }
        }

        static int counter = 0;
        static void DoTest()
        {
            counter++;
            Debug.WriteLine($"Do Test jump to function {counter}");
        }

        private static T Identity<T>(T value)
        {
            return value;
        }
    }
namespace TinyCLRApp10_Task2 {
    class Program {
        static async Task Main() {
            Debug.WriteLine("=== TinyCLR Async/Await Test ===");

            // 1. Basic await of a Task that does real work + delay
            Debug.WriteLine("[1] Start");
            await DoWorkAsync();
            Debug.WriteLine("[1] End");

            // 2. Task<T> with a return value
            Debug.WriteLine("[2] Computing...");
            var answer = await ComputeAsync(20, 22);
            Debug.WriteLine("[2] 20 + 22 = " + answer.ToString());

            // 3. Task.FromResult - already-completed task
            var preset = Task.FromResult(100);
            var val = await preset;
            Debug.WriteLine("[3] FromResult = " + val.ToString());

            // 4. Sequential awaits - no parallelism expected, each runs fully
            Debug.WriteLine("[4] Sequential 3 x 500 ms...");
            var startTicks = DateTime.UtcNow.Ticks;
            await Task.Delay(500);
            await Task.Delay(500);
            await Task.Delay(500);
            var elapsedMs = (DateTime.UtcNow.Ticks - startTicks) / TimeSpan.TicksPerMillisecond;
            Debug.WriteLine("[4] Elapsed ~" + elapsedMs.ToString() + " ms (expect ~1500)");

            // 5. Nested async calls
            Debug.WriteLine("[5] Nested...");
            await OuterAsync();
            Debug.WriteLine("[5] Back in Main");

            // 6. Mixed sync work between awaits
            Debug.WriteLine("[6] Counting...");
            for (var i = 1; i <= 3; i++) {
                await Task.Delay(300);
                Debug.WriteLine("[6] tick " + i.ToString());
            }

            Debug.WriteLine("=== All tests passed ===");

            var cnt = 0;
            while (true) {
                Debug.WriteLine("alive " + (cnt++).ToString());
                Thread.Sleep(1000);
            }
        }

        static async Task DoWorkAsync() {
            Debug.WriteLine("    Working...");
            await Task.Delay(2000);
            Debug.WriteLine("    Done");
        }

        static async Task<int> ComputeAsync(int a, int b) {
            await Task.Delay(200);
            return a + b;
        }

        static async Task OuterAsync() {
            Debug.WriteLine("    Outer begin");
            await InnerAsync();
            Debug.WriteLine("    Outer end");
        }

        static async Task InnerAsync() {
            Debug.WriteLine("      Inner begin");
            await Task.Delay(300);
            Debug.WriteLine("      Inner end");
        }
    }
}

namespace TinyCLRApp10_List {
    
    class Program {
    

        static void Main()
        {
            var list = new System.Collections.Generic.List<int>();
            list.Add(1);
            list.Add(2);
            list.Add(3);
            Debug.WriteLine(list.Count.ToString()); // 3

            foreach (var item in list)
                Debug.WriteLine(item.ToString()); // 1, 2, 3

   
            list.Remove(2);
            Debug.WriteLine(list.Count.ToString()); // 2
            var cnt = 0;
            while (true) {
                Debug.WriteLine("Hello from TinyCLR! Count: " + cnt++);
                Thread.Sleep(1000);
            }
        }
    }
}
namespace TinyCLRApp10_Tuble {
    class Program {
        static void Main() {
            Console.WriteLine("=== Tuple test ===");

            // 1. Basic 2-tuple via factory
            var pair = Tuple.Create(42, "hello");
            Debug.WriteLine("[1] Item1 = " + pair.Item1.ToString());
            Debug.WriteLine("[1] Item2 = " + pair.Item2);
            Debug.WriteLine("[1] ToString = " + pair.ToString());   // (42, hello)

            // 2. 3-tuple of ints
            var coords = Tuple.Create(10, 20, 30);
            Debug.WriteLine("[2] coords = " + coords.ToString());   // (10, 20, 30)
            Debug.WriteLine("[2] sum = " + (coords.Item1 + coords.Item2 + coords.Item3).ToString());

            // 3. Value-based equality
            var a = Tuple.Create(1, 2);
            var b = Tuple.Create(1, 2);
            var c = Tuple.Create(1, 3);
            Debug.WriteLine("[3] a.Equals(b) = " + a.Equals(b).ToString());   // True
            Debug.WriteLine("[3] a.Equals(c) = " + a.Equals(c).ToString());   // False
            Debug.WriteLine("[3] ReferenceEquals(a,b) = " + object.ReferenceEquals(a, b).ToString());   // False

            // 4. Hash codes: equal tuples -> same hash
            Debug.WriteLine("[4] a.GetHashCode == b.GetHashCode : "
                + (a.GetHashCode() == b.GetHashCode()).ToString());   // True

            // 5. Tuple as a return value (the classic use case)
            var result = Divide(17, 5);
            Debug.WriteLine("[5] 17 / 5 = " + result.Item1.ToString() + " remainder " + result.Item2.ToString());

            // 6. Nullable / mixed types (5-arity)
            var t5 = new Tuple<int, string, bool, int, string>(1, "two", true, 4, "five");
            Debug.WriteLine("[6] t5 = " + t5.ToString());
            Debug.WriteLine("[6] t5.Item3 = " + t5.Item3.ToString());

            // 7. Tuple with null element
            var withNull = Tuple.Create<string, string>("A", null);
            Debug.WriteLine("[7] withNull = " + withNull.ToString());   // (A, )

            Debug.WriteLine("=== Done ===");

            var cnt = 0;
            while (true) {
                Debug.WriteLine("alive " + (cnt++).ToString());
                Thread.Sleep(1000);
            }
        }

        // Classic pattern: return two values without an out parameter
        static Tuple<int, int> Divide(int a, int b) => Tuple.Create(a / b, a % b);
    }
}

This is not a promise yet, as it depends on last-minute approval, but it has already been added and is running on TinyCLR.

5 Likes