/// <summary> /// Creates a descriptor for generated code. /// </summary> /// <remarks> /// This method is only designed to be used by the results of generating code with protoc, /// which creates the appropriate dependencies etc. It has to be public because the generated /// code is "external", but should not be called directly by end users. /// </remarks> public static FileDescriptor FromGeneratedCode( byte[] descriptorData, FileDescriptor[] dependencies, GeneratedClrTypeInfo generatedCodeInfo) { ExtensionRegistry registry = new ExtensionRegistry(); registry.AddRange(GetAllExtensions(dependencies, generatedCodeInfo)); FileDescriptorProto proto; try { proto = FileDescriptorProto.Parser.WithExtensionRegistry(registry).ParseFrom(descriptorData); } catch (InvalidProtocolBufferException e) { throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e); } try { // When building descriptors for generated code, we allow unknown // dependencies by default. return(BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, true, generatedCodeInfo)); } catch (DescriptorValidationException e) { throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e); } }
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedClrTypeInfo generatedCodeInfo) : base(file, file.ComputeFullName(parent, proto.Name), typeIndex) { Proto = proto; Parser = generatedCodeInfo?.Parser; ClrType = generatedCodeInfo?.ClrType; ContainingType = parent; // If generatedCodeInfo is null, we just won't generate an accessor for any fields. Oneofs = DescriptorUtil.ConvertAndMakeReadOnly( proto.OneofDecl, (oneof, index) => new OneofDescriptor(oneof, file, this, index, generatedCodeInfo?.OneofNames[index])); int syntheticOneofCount = 0; foreach (var oneof in Oneofs) { if (oneof.IsSynthetic) { syntheticOneofCount++; } else if (syntheticOneofCount != 0) { throw new ArgumentException("All synthetic oneofs should come after real oneofs"); } } RealOneofCount = Oneofs.Count - syntheticOneofCount; NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly( proto.NestedType, (type, index) => new MessageDescriptor(type, file, this, index, generatedCodeInfo?.NestedTypes[index])); EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly( proto.EnumType, (type, index) => new EnumDescriptor(type, file, this, index, generatedCodeInfo?.NestedEnums[index])); Extensions = new ExtensionCollection(this, generatedCodeInfo?.Extensions); fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly( proto.Field, (field, index) => new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index], null)); fieldsInNumberOrder = new ReadOnlyCollection <FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray()); // TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.) jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder); file.DescriptorPool.AddSymbol(this); Fields = new FieldCollection(this); }
private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, IEnumerable <FileDescriptor> dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) { SerializedData = descriptorData; DescriptorPool = pool; Proto = proto; Dependencies = new ReadOnlyCollection <FileDescriptor>(dependencies.ToList()); PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies); pool.AddPackage(Package, this); MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType, (message, index) => new MessageDescriptor(message, this, null, index, generatedCodeInfo?.NestedTypes[index])); EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType, (enumType, index) => new EnumDescriptor(enumType, this, null, index, generatedCodeInfo?.NestedEnums[index])); Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service, (service, index) => new ServiceDescriptor(service, this, index)); Extensions = new ExtensionCollection(this, generatedCodeInfo?.Extensions); declarations = new Lazy <Dictionary <IDescriptor, DescriptorDeclaration> >(CreateDeclarationMap, LazyThreadSafetyMode.ExecutionAndPublication); if (!proto.HasSyntax || proto.Syntax == "proto2") { Syntax = Syntax.Proto2; } else if (proto.Syntax == "proto3") { Syntax = Syntax.Proto3; } else { Syntax = Syntax.Unknown; } }
private static IEnumerable <Extension> GetAllGeneratedExtensions(GeneratedClrTypeInfo generated) { return(generated.Extensions.Concat(generated.NestedTypes.Where(t => t != null).SelectMany(GetAllGeneratedExtensions))); }
private static IEnumerable <Extension> GetAllExtensions(FileDescriptor[] dependencies, GeneratedClrTypeInfo generatedInfo) { return(dependencies.SelectMany(GetAllDependedExtensions).Distinct(ExtensionRegistry.ExtensionComparer.Instance).Concat(GetAllGeneratedExtensions(generatedInfo))); }
/// <summary> /// Builds a FileDescriptor from its protocol buffer representation. /// </summary> /// <param name="descriptorData">The original serialized descriptor data. /// We have only limited proto2 support, so serializing FileDescriptorProto /// would not necessarily give us this.</param> /// <param name="proto">The protocol message form of the FileDescriptor.</param> /// <param name="dependencies">FileDescriptors corresponding to all of the /// file's dependencies, in the exact order listed in the .proto file. May be null, /// in which case it is treated as an empty array.</param> /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param> /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param> /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not /// a valid descriptor. This can occur for a number of reasons, such as a field /// having an undefined type or because two messages were defined with the same name.</exception> private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) { // Building descriptors involves two steps: translating and linking. // In the translation step (implemented by FileDescriptor's // constructor), we build an object tree mirroring the // FileDescriptorProto's tree and put all of the descriptors into the // DescriptorPool's lookup tables. In the linking step, we look up all // type references in the DescriptorPool, so that, for example, a // FieldDescriptor for an embedded message contains a pointer directly // to the Descriptor for that message's type. We also detect undefined // types in the linking step. if (dependencies == null) { dependencies = new FileDescriptor[0]; } DescriptorPool pool = new DescriptorPool(dependencies); FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo); // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we // need. if (dependencies.Length != proto.Dependency.Count) { throw new DescriptorValidationException( result, "Dependencies passed to FileDescriptor.BuildFrom() don't match " + "those listed in the FileDescriptorProto."); } result.CrossLink(); return(result); }