/* deserialization of entire list. generates code like:
         *
         *  static public void ReadStructBuf(NetworkReader reader, SyncListBuf instance)
         *  {
         *      ushort count = reader.ReadUInt16();
         *      instance.Clear()
         *      for (ushort i = 0; i < count; i++)
         *      {
         *          instance.AddInternal(instance.DeserializeItem(reader));
         *      }
         *  }
         */
        void GenerateReadFunc(MethodReference readItemFunc)
        {
            var functionName = "_ReadStruct" + m_TypeDef.Name + "_";

            if (m_TypeDef.DeclaringType != null)
            {
                functionName += m_TypeDef.DeclaringType.Name;
            }
            else
            {
                functionName += "None";
            }

            // create new reader for this type
            MethodDefinition readerFunc = new MethodDefinition(functionName,
                                                               MethodAttributes.Public |
                                                               MethodAttributes.Static |
                                                               MethodAttributes.HideBySig,
                                                               Weaver.voidType);

            readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
            readerFunc.Parameters.Add(new ParameterDefinition("instance", ParameterAttributes.None, m_TypeDef));

            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
            readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
            readerFunc.Body.InitLocals = true;

            ILProcessor worker = readerFunc.Body.GetILProcessor();

            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Callvirt, Weaver.NetworkReadUInt16));
            worker.Append(worker.Create(OpCodes.Stloc_0));

            // Call Clear() from the base class
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            MethodReference genericClearMethod = Helpers.MakeHostInstanceGeneric(Weaver.SyncListClear, m_ItemType);

            worker.Append(worker.Create(OpCodes.Callvirt, genericClearMethod));

            worker.Append(worker.Create(OpCodes.Ldc_I4_0));
            worker.Append(worker.Create(OpCodes.Stloc_1));
            var loopCheckLabel = worker.Create(OpCodes.Nop);

            worker.Append(worker.Create(OpCodes.Br, loopCheckLabel));

            // loop body
            var loopHeadLabel = worker.Create(OpCodes.Nop);

            worker.Append(loopHeadLabel);

            worker.Append(worker.Create(OpCodes.Ldarg_1));
            worker.Append(worker.Create(OpCodes.Ldarg_1));

            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Callvirt, readItemFunc));

            // call the generic AddInternal from the base class
            var addInternal      = Weaver.ResolveMethod(Weaver.SyncListStructType, "AddInternal");
            var addInternalTyped = Helpers.MakeHostInstanceGeneric(addInternal, m_ItemType);

            worker.Append(worker.Create(OpCodes.Callvirt, addInternalTyped));

            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldc_I4_1));
            worker.Append(worker.Create(OpCodes.Add));
            worker.Append(worker.Create(OpCodes.Conv_U2));
            worker.Append(worker.Create(OpCodes.Stloc_1));

            // loop check
            worker.Append(loopCheckLabel);
            worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ldloc_0));
            worker.Append(worker.Create(OpCodes.Blt, loopHeadLabel));

            // done
            //worker.Append(worker.Create(OpCodes.Ldloc_1));
            worker.Append(worker.Create(OpCodes.Ret));

            Weaver.RegisterReadByReferenceFunc(m_TypeDef.FullName, readerFunc);
        }