-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
26672fd6.c8be9bb4.js
1 lines (1 loc) · 9.49 KB
/
26672fd6.c8be9bb4.js
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{119:function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return u}));var a=n(0),o=n.n(a);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?s(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),c=function(e){var t=o.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=c(e.components);return o.a.createElement(p.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},b=o.a.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=c(n),b=a,u=d["".concat(s,".").concat(b)]||d[b]||m[b]||r;return n?o.a.createElement(u,l(l({ref:t},p),{},{components:n})):o.a.createElement(u,l({ref:t},p))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=b;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:a,s[1]=l;for(var p=2;p<r;p++)s[p]=n[p];return o.a.createElement.apply(null,s)}return o.a.createElement.apply(null,n)}b.displayName="MDXCreateElement"},80:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return l})),n.d(t,"metadata",(function(){return i})),n.d(t,"toc",(function(){return p})),n.d(t,"default",(function(){return d}));var a=n(3),o=n(7),r=(n(0),n(119)),s=["components"],l={title:"Sealed oneofs"},i={unversionedId:"sealed-oneofs",id:"sealed-oneofs",isDocsHomePage:!1,title:"Sealed oneofs",description:"Sealed oneofs are a subset of oneofs for which ScalaPB generates idiomatic data types for.",source:"@site/../docs/target/mdoc/sealed-oneofs.md",slug:"/sealed-oneofs",permalink:"/docs/sealed-oneofs",version:"current",sidebar:"someSidebar",previous:{title:"Generated Code",permalink:"/docs/generated-code"},next:{title:"Defining custom options",permalink:"/docs/user_defined_options"}},p=[{value:"Example",id:"example",children:[]},{value:"Sealed oneof rules",id:"sealed-oneof-rules",children:[]},{value:"Optional sealed oneof",id:"optional-sealed-oneof",children:[]}],c={toc:p};function d(e){var t=e.components,n=Object(o.a)(e,s);return Object(r.b)("wrapper",Object(a.a)({},c,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Sealed oneofs are a subset of oneofs for which ScalaPB generates idiomatic data types for."),Object(r.b)("h2",{id:"example"},"Example"),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-protobuf"},"message Expr {\n oneof sealed_value {\n Literal lit = 1;\n Add add = 2;\n Mul mul = 3;\n }\n}\n\nmessage Literal {\n int32 value = 1;\n}\n\nmessage Add {\n Expr left = 1;\n Expr right = 2;\n}\n\nmessage Mul {\n Expr left = 1;\n Expr right = 2;\n}\n\nmessage Program {\n repeated Expr exprs = 1;\n}\n")),Object(r.b)("p",null,"Note that the name of the oneof name is ",Object(r.b)("inlineCode",{parentName:"p"},"sealed_value"),". This is what makes ScalaPB treat ",Object(r.b)("inlineCode",{parentName:"p"},"Expr")," as a sealed oneof and generate code similar to the following:"),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-scala"},"sealed trait Expr {\n def isEmpty: Boolean\n def isDefined: Boolean\n def asMessage: ExprMessage // converts to the standard representation\n}\n\nobject Expr {\n case object Empty extends Expr\n}\n\ncase class Literal(value: Int) extends Expr with GeneratedMessage\n\ncase class Add(left: Expr, right: Expr) extends Expr with GeneratedMessage\n\ncase class Mul(left: Expr, right: Expr) extends Expr with GeneratedMessage\n\ncase class Programs(exprs: Seq[Expr]) extends GeneratedMessage\n\n// Standard case class for the Expr message, containing the\n// default style of the code that gets generated for oneofs.\ncase class ExprMessage(sealedValue: ExprMessage.SealedValue)\n")),Object(r.b)("p",null,"The above Scala representation of the protocol buffer is much nicer to work with than the default oneof representation, as there are no wrapper types around each individual case of the oneof. Also note that optional fields of type ",Object(r.b)("inlineCode",{parentName:"p"},"Expr")," are not boxed inside an ",Object(r.b)("inlineCode",{parentName:"p"},"Option")," since we have ",Object(r.b)("inlineCode",{parentName:"p"},"Expr.Empty")," that represents the empty case."),Object(r.b)("h2",{id:"sealed-oneof-rules"},"Sealed oneof rules"),Object(r.b)("p",null,"A sealed oneof is detected when a message (denoted below as the ",Object(r.b)("em",{parentName:"p"},"containing message"),") contains a oneof named ",Object(r.b)("inlineCode",{parentName:"p"},"sealed_value"),". The code generator checks the following rules for each sealed oneof. If any of these rules fail, then the code generator aborts."),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"The oneof named ",Object(r.b)("inlineCode",{parentName:"p"},"sealed_value")," must be the only oneof in the containing message.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"No additional fields (except those inside ",Object(r.b)("inlineCode",{parentName:"p"},"sealed_values"),") may be defined inside the containing message.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"No nested messages or enums are allowed to be defined in the containing message.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"All of the oneof cases must be inside the same namespace as the containing message. That is, all messages must either be top-level or direct children of the same parent message.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"All the oneof cases must defined in the same file as the sealed oneof.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"A message type can appear in at most one sealed oneof.")),Object(r.b)("li",{parentName:"ol"},Object(r.b)("p",{parentName:"li"},"Sealed oneofs and the fields within them can not be typemapped to custom\ntypes."))),Object(r.b)("p",null,"Some of the rules above are inherently required (for example, that the message types need to be distinct). Other rules, such as the one requesting that all involved messages need to be inside the same namespace, were added to make the implementation simpler. That particular rule helps ensuring that all the cases can be generated into a single Scala source file without changing too much the existing way the code generator works. It is possible that some of the rules will change over time, though most likely they are only going to become less restrictive so existing code does not break."),Object(r.b)("p",null,"Currently, sealed oneofs are implemented as a custom type defined over the old-style container message. This implementation detail is exposed through ",Object(r.b)("inlineCode",{parentName:"p"},"asMessage")," which returns the underlying message representing the sealed oneof. It is possible that in a future version, sealed oneofs would have a direct implementation, and therefore ",Object(r.b)("inlineCode",{parentName:"p"},"asMessage")," and its return type should be considered an experimental API."),Object(r.b)("h2",{id:"optional-sealed-oneof"},"Optional sealed oneof"),Object(r.b)("p",null,"This is a variant of ",Object(r.b)("em",{parentName:"p"},"Sealed oneof"),", where the optionality is expressed differently.\nThe ",Object(r.b)("inlineCode",{parentName:"p"},"Empty")," case is not generated, but instead the sealed trait is put in other classes as ",Object(r.b)("inlineCode",{parentName:"p"},"Option[_]"),", not directly.\nTo create an optional sealed oneof, name the oneof sealed_value_optional as in the example below:"),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-protobuf"},"message Expr {\n oneof sealed_value_optional {\n Literal lit = 1;\n Add add = 2;\n Mul mul = 3;\n }\n}\n")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-scala"},"sealed trait Expr {\n def isEmpty: Boolean\n def isDefined: Boolean\n def asMessage: ExprMessage // converts to the standard representation\n}\n\ncase class Literal(value: Int) extends Expr with GeneratedMessage\n\ncase class Add(left: Option[Expr], right: Option[Expr]) extends Expr with GeneratedMessage\n\ncase class Mul(left: Option[Expr], right: Option[Expr]) extends Expr with GeneratedMessage\n\ncase class Programs(exprs: Seq[Option[Expr]]) extends GeneratedMessage\n")))}d.isMDXComponent=!0}}]);